From nobody Sun Apr 5 18:56:19 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 0D9AB3BED27 for ; Mon, 23 Mar 2026 16:39:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774283972; cv=none; b=mGyCAUhbMOHEtBUISMfxt4IoTzrvwlo1K7f8nTZ2aCx5r/eu/EBy5YoJLvCNTAGi8Vg+/g2N9rYf+dXZJQaDmJ3424Eblfo8k3eiVsAzPZCxtRQvoaKJ4vxbkxrigsNBS/o27Vltl2d01I8uiASRx5y4/7lUso5DpBIQ1gYg8O0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774283972; c=relaxed/simple; bh=msQeNtH7U/c9RGW6g2Fu6w7ImvbfoePDsipOdRo3Ve8=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=utUjTUmCViKHXUfpa62yP2LMXJ1VS2mnFs25mGz7kKWuzR7Nlq0QdqZuutPRD33ojeUba8BCRaeKhpPjxrQVmX8gUTwiKmxmbkR3YqF1Kf+bFtJfFELtyR0WbRc3hF27dKaIqujVZrpFjboM74hS5Zin+bjPOzi1+/hxG5EEu4A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 424D414BF; Mon, 23 Mar 2026 09:39:23 -0700 (PDT) Received: from e125769.cambridge.arm.com (e125769.cambridge.arm.com [10.1.196.27]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 37D8D3F73B; Mon, 23 Mar 2026 09:39:28 -0700 (PDT) From: Ryan Roberts To: Catalin Marinas , Will Deacon , Anshuman Khandual , Linu Cherian Cc: Ryan Roberts , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Aishwarya TCV Subject: [PATCH v1] arm64: mm: __ptep_set_access_flags must hint correct TTL Date: Mon, 23 Mar 2026 16:39:16 +0000 Message-ID: <20260323163918.2028109-1-ryan.roberts@arm.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" It has been reported that since commit 752a0d1d483e9 ("arm64: mm: Provide level hint for flush_tlb_page()"), the arm64 check_hugetlb_options selftest has been locking up while running "Check child hugetlb memory with private mapping, sync error mode and mmap memory". This is due to hugetlb (and THP) helpers casting their PMD/PUD entries to PTE and calling __ptep_set_access_flags(), which issues a __flush_tlb_page(). Now that this is hinted for level 3, in this case, the TLB entry does not get evicted and we end up in a spurious fault loop. Fix this by creating a __ptep_set_access_flags_anysz() function which takes the pgsize of the entry. It can then add the appropriate hint. The "_anysz" approach is the established pattern for problems of this class. Reported-by: Aishwarya TCV Fixes: 752a0d1d483e9 ("arm64: mm: Provide level hint for flush_tlb_page()") Signed-off-by: Ryan Roberts --- Applies on top of for-next/tlbflush. mm selftests run and pass in VM on App= le M2. arm64 check_hugetlb_options selftest runs and passed on FVP configured = with MTE enabled. Thanks, Ryan arch/arm64/include/asm/pgtable.h | 19 ++++++++++++++----- arch/arm64/mm/fault.c | 30 +++++++++++++++++++++++++----- arch/arm64/mm/hugetlbpage.c | 6 +++--- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgta= ble.h index b1a96a8f2b17e..53e39d2182f5a 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -1248,9 +1248,18 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t n= ewprot) return pte_pmd(pte_modify(pmd_pte(pmd), newprot)); } -extern int __ptep_set_access_flags(struct vm_area_struct *vma, - unsigned long address, pte_t *ptep, - pte_t entry, int dirty); +extern int __ptep_set_access_flags_anysz(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep, + pte_t entry, int dirty, + unsigned long pgsize); + +static inline int __ptep_set_access_flags(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep, + pte_t entry, int dirty) +{ + return __ptep_set_access_flags_anysz(vma, address, ptep, entry, dirty, + PAGE_SIZE); +} #ifdef CONFIG_TRANSPARENT_HUGEPAGE #define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS @@ -1258,8 +1267,8 @@ static inline int pmdp_set_access_flags(struct vm_are= a_struct *vma, unsigned long address, pmd_t *pmdp, pmd_t entry, int dirty) { - return __ptep_set_access_flags(vma, address, (pte_t *)pmdp, - pmd_pte(entry), dirty); + return __ptep_set_access_flags_anysz(vma, address, (pte_t *)pmdp, + pmd_pte(entry), dirty, PMD_SIZE); } #endif diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index f91aa686f1428..920a8b244d59e 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -204,12 +204,13 @@ static void show_pte(unsigned long addr) * * Returns whether or not the PTE actually changed. */ -int __ptep_set_access_flags(struct vm_area_struct *vma, - unsigned long address, pte_t *ptep, - pte_t entry, int dirty) +int __ptep_set_access_flags_anysz(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep, + pte_t entry, int dirty, unsigned long pgsize) { pteval_t old_pteval, pteval; pte_t pte =3D __ptep_get(ptep); + int level; if (pte_same(pte, entry)) return 0; @@ -238,8 +239,27 @@ int __ptep_set_access_flags(struct vm_area_struct *vma, * may still cause page faults and be invalidated via * flush_tlb_fix_spurious_fault(). */ - if (dirty) - __flush_tlb_page(vma, address, TLBF_NOBROADCAST); + if (dirty) { + switch (pgsize) { + case PAGE_SIZE: + level =3D 3; + break; + case PMD_SIZE: + level =3D 2; + break; +#ifndef __PAGETABLE_PMD_FOLDED + case PUD_SIZE: + level =3D 1; + break; +#endif + default: + level =3D TLBI_TTL_UNKNOWN; + WARN_ON(1); + } + + __flush_tlb_range(vma, address, address + pgsize, pgsize, level, + TLBF_NOWALKCACHE | TLBF_NOBROADCAST); + } return 1; } diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c index 0b7ccd0cbb9ec..30772a909aea3 100644 --- a/arch/arm64/mm/hugetlbpage.c +++ b/arch/arm64/mm/hugetlbpage.c @@ -427,11 +427,11 @@ int huge_ptep_set_access_flags(struct vm_area_struct = *vma, pte_t orig_pte; VM_WARN_ON(!pte_present(pte)); + ncontig =3D num_contig_ptes(huge_page_size(hstate_vma(vma)), &pgsize); if (!pte_cont(pte)) - return __ptep_set_access_flags(vma, addr, ptep, pte, dirty); - - ncontig =3D num_contig_ptes(huge_page_size(hstate_vma(vma)), &pgsize); + return __ptep_set_access_flags_anysz(vma, addr, ptep, pte, + dirty, pgsize); if (!__cont_access_flags_changed(ptep, pte, ncontig)) return 0; -- 2.43.0