]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-client.git/commitdiff
arm64: mm: support batch clearing of the young flag for large folios
authorBaolin Wang <baolin.wang@linux.alibaba.com>
Mon, 9 Feb 2026 14:07:26 +0000 (22:07 +0800)
committerAndrew Morton <akpm@linux-foundation.org>
Thu, 12 Feb 2026 23:43:00 +0000 (15:43 -0800)
Currently, contpte_ptep_test_and_clear_young() and
contpte_ptep_clear_flush_young() only clear the young flag and flush TLBs
for PTEs within the contiguous range.  To support batch PTE operations for
other sized large folios in the following patches, adding a new parameter
to specify the number of PTEs that map consecutive pages of the same large
folio in a single VMA and a single page table.

While we are at it, rename the functions to maintain consistency with
other contpte_*() functions.

Link: https://lkml.kernel.org/r/5644250dcc0417278c266ad37118d27f541fd052.1770645603.git.baolin.wang@linux.alibaba.com
Signed-off-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Reviewed-by: Ryan Roberts <ryan.roberts@arm.com>
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
Cc: Barry Song <baohua@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Harry Yoo <harry.yoo@oracle.com>
Cc: Jann Horn <jannh@google.com>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Rik van Riel <riel@surriel.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
arch/arm64/include/asm/pgtable.h
arch/arm64/mm/contpte.c

index d94445b4f3dfafcda88c7953a84228d39f788f3a..3dabf5ea17faff8ae9a0ffc1d573aa79c6d55d76 100644 (file)
@@ -1648,10 +1648,10 @@ extern void contpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr,
 extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
                                unsigned long addr, pte_t *ptep,
                                unsigned int nr, int full);
-extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
-                               unsigned long addr, pte_t *ptep);
-extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
-                               unsigned long addr, pte_t *ptep);
+int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
+                               unsigned long addr, pte_t *ptep, unsigned int nr);
+int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
+                               unsigned long addr, pte_t *ptep, unsigned int nr);
 extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
                                pte_t *ptep, unsigned int nr);
 extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
@@ -1823,7 +1823,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
        if (likely(!pte_valid_cont(orig_pte)))
                return __ptep_test_and_clear_young(vma, addr, ptep);
 
-       return contpte_ptep_test_and_clear_young(vma, addr, ptep);
+       return contpte_test_and_clear_young_ptes(vma, addr, ptep, 1);
 }
 
 #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
@@ -1835,7 +1835,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
        if (likely(!pte_valid_cont(orig_pte)))
                return __ptep_clear_flush_young(vma, addr, ptep);
 
-       return contpte_ptep_clear_flush_young(vma, addr, ptep);
+       return contpte_clear_flush_young_ptes(vma, addr, ptep, 1);
 }
 
 #define wrprotect_ptes wrprotect_ptes
index e4ddeb46f25d6e03a8f26b20d0a1ad3249a6414d..b929a455103f877ab763ebc71467c529757d8539 100644 (file)
@@ -508,8 +508,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
 }
 EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);
 
-int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
-                                       unsigned long addr, pte_t *ptep)
+int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
+                                       unsigned long addr, pte_t *ptep,
+                                       unsigned int nr)
 {
        /*
         * ptep_clear_flush_young() technically requires us to clear the access
@@ -518,41 +519,45 @@ int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
         * contig range when the range is covered by a single folio, we can get
         * away with clearing young for the whole contig range here, so we avoid
         * having to unfold.
+        *
+        * The 'nr' means consecutive (present) PTEs that map consecutive pages
+        * of the same large folio in a single VMA and a single page table.
         */
 
+       unsigned long end = addr + nr * PAGE_SIZE;
        int young = 0;
-       int i;
 
-       ptep = contpte_align_down(ptep);
-       addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
-
-       for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
+       ptep = contpte_align_addr_ptep(&addr, &end, ptep, nr);
+       for (; addr != end; ptep++, addr += PAGE_SIZE)
                young |= __ptep_test_and_clear_young(vma, addr, ptep);
 
        return young;
 }
-EXPORT_SYMBOL_GPL(contpte_ptep_test_and_clear_young);
+EXPORT_SYMBOL_GPL(contpte_test_and_clear_young_ptes);
 
-int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
-                                       unsigned long addr, pte_t *ptep)
+int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
+                               unsigned long addr, pte_t *ptep,
+                               unsigned int nr)
 {
        int young;
 
-       young = contpte_ptep_test_and_clear_young(vma, addr, ptep);
+       young = contpte_test_and_clear_young_ptes(vma, addr, ptep, nr);
 
        if (young) {
+               unsigned long end = addr + nr * PAGE_SIZE;
+
+               contpte_align_addr_ptep(&addr, &end, ptep, nr);
                /*
                 * See comment in __ptep_clear_flush_young(); same rationale for
                 * eliding the trailing DSB applies here.
                 */
-               addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
-               __flush_tlb_range_nosync(vma->vm_mm, addr, addr + CONT_PTE_SIZE,
+               __flush_tlb_range_nosync(vma->vm_mm, addr, end,
                                         PAGE_SIZE, true, 3);
        }
 
        return young;
 }
-EXPORT_SYMBOL_GPL(contpte_ptep_clear_flush_young);
+EXPORT_SYMBOL_GPL(contpte_clear_flush_young_ptes);
 
 void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
                                        pte_t *ptep, unsigned int nr)