]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mm/page_table_check: Batch-check pmds/puds just like ptes
authorRyan Roberts <ryan.roberts@arm.com>
Tue, 22 Apr 2025 08:18:11 +0000 (09:18 +0100)
committerWill Deacon <will@kernel.org>
Fri, 9 May 2025 12:43:07 +0000 (13:43 +0100)
Convert page_table_check_p[mu]d_set(...) to
page_table_check_p[mu]ds_set(..., nr) to allow checking a contiguous set
of pmds/puds in single batch. We retain page_table_check_p[mu]d_set(...)
as macros that call new batch functions with nr=1 for compatibility.

arm64 is about to reorganise its pte/pmd/pud helpers to reuse more code
and to allow the implementation for huge_pte to more efficiently set
ptes/pmds/puds in batches. We need these batch-helpers to make the
refactoring possible.

Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
Tested-by: Luiz Capitulino <luizcap@redhat.com>
Link: https://lore.kernel.org/r/20250422081822.1836315-4-ryan.roberts@arm.com
Signed-off-by: Will Deacon <will@kernel.org>
include/linux/page_table_check.h
mm/page_table_check.c

index 6722941c7cb8a6b3d5a4549d972f767db820f18d..289620d4aad3a03a0c3b27b08066fb27250cd10a 100644 (file)
@@ -19,8 +19,10 @@ void __page_table_check_pmd_clear(struct mm_struct *mm, pmd_t pmd);
 void __page_table_check_pud_clear(struct mm_struct *mm, pud_t pud);
 void __page_table_check_ptes_set(struct mm_struct *mm, pte_t *ptep, pte_t pte,
                unsigned int nr);
-void __page_table_check_pmd_set(struct mm_struct *mm, pmd_t *pmdp, pmd_t pmd);
-void __page_table_check_pud_set(struct mm_struct *mm, pud_t *pudp, pud_t pud);
+void __page_table_check_pmds_set(struct mm_struct *mm, pmd_t *pmdp, pmd_t pmd,
+               unsigned int nr);
+void __page_table_check_puds_set(struct mm_struct *mm, pud_t *pudp, pud_t pud,
+               unsigned int nr);
 void __page_table_check_pte_clear_range(struct mm_struct *mm,
                                        unsigned long addr,
                                        pmd_t pmd);
@@ -74,22 +76,22 @@ static inline void page_table_check_ptes_set(struct mm_struct *mm,
        __page_table_check_ptes_set(mm, ptep, pte, nr);
 }
 
-static inline void page_table_check_pmd_set(struct mm_struct *mm, pmd_t *pmdp,
-                                           pmd_t pmd)
+static inline void page_table_check_pmds_set(struct mm_struct *mm,
+               pmd_t *pmdp, pmd_t pmd, unsigned int nr)
 {
        if (static_branch_likely(&page_table_check_disabled))
                return;
 
-       __page_table_check_pmd_set(mm, pmdp, pmd);
+       __page_table_check_pmds_set(mm, pmdp, pmd, nr);
 }
 
-static inline void page_table_check_pud_set(struct mm_struct *mm, pud_t *pudp,
-                                           pud_t pud)
+static inline void page_table_check_puds_set(struct mm_struct *mm,
+               pud_t *pudp, pud_t pud, unsigned int nr)
 {
        if (static_branch_likely(&page_table_check_disabled))
                return;
 
-       __page_table_check_pud_set(mm, pudp, pud);
+       __page_table_check_puds_set(mm, pudp, pud, nr);
 }
 
 static inline void page_table_check_pte_clear_range(struct mm_struct *mm,
@@ -129,13 +131,13 @@ static inline void page_table_check_ptes_set(struct mm_struct *mm,
 {
 }
 
-static inline void page_table_check_pmd_set(struct mm_struct *mm, pmd_t *pmdp,
-                                           pmd_t pmd)
+static inline void page_table_check_pmds_set(struct mm_struct *mm,
+               pmd_t *pmdp, pmd_t pmd, unsigned int nr)
 {
 }
 
-static inline void page_table_check_pud_set(struct mm_struct *mm, pud_t *pudp,
-                                           pud_t pud)
+static inline void page_table_check_puds_set(struct mm_struct *mm,
+               pud_t *pudp, pud_t pud, unsigned int nr)
 {
 }
 
@@ -146,4 +148,8 @@ static inline void page_table_check_pte_clear_range(struct mm_struct *mm,
 }
 
 #endif /* CONFIG_PAGE_TABLE_CHECK */
+
+#define page_table_check_pmd_set(mm, pmdp, pmd)        page_table_check_pmds_set(mm, pmdp, pmd, 1)
+#define page_table_check_pud_set(mm, pudp, pud)        page_table_check_puds_set(mm, pudp, pud, 1)
+
 #endif /* __LINUX_PAGE_TABLE_CHECK_H */
index 68109ee93841d51bd3b7ef428327a11489770732..4eeca782b8887a1adc0543a39e74f6d2c9ecab8e 100644 (file)
@@ -218,33 +218,39 @@ static inline void page_table_check_pmd_flags(pmd_t pmd)
                WARN_ON_ONCE(swap_cached_writable(pmd_to_swp_entry(pmd)));
 }
 
-void __page_table_check_pmd_set(struct mm_struct *mm, pmd_t *pmdp, pmd_t pmd)
+void __page_table_check_pmds_set(struct mm_struct *mm, pmd_t *pmdp, pmd_t pmd,
+               unsigned int nr)
 {
+       unsigned long stride = PMD_SIZE >> PAGE_SHIFT;
+       unsigned int i;
+
        if (&init_mm == mm)
                return;
 
        page_table_check_pmd_flags(pmd);
 
-       __page_table_check_pmd_clear(mm, *pmdp);
-       if (pmd_user_accessible_page(pmd)) {
-               page_table_check_set(pmd_pfn(pmd), PMD_SIZE >> PAGE_SHIFT,
-                                    pmd_write(pmd));
-       }
+       for (i = 0; i < nr; i++)
+               __page_table_check_pmd_clear(mm, *(pmdp + i));
+       if (pmd_user_accessible_page(pmd))
+               page_table_check_set(pmd_pfn(pmd), stride * nr, pmd_write(pmd));
 }
-EXPORT_SYMBOL(__page_table_check_pmd_set);
+EXPORT_SYMBOL(__page_table_check_pmds_set);
 
-void __page_table_check_pud_set(struct mm_struct *mm, pud_t *pudp, pud_t pud)
+void __page_table_check_puds_set(struct mm_struct *mm, pud_t *pudp, pud_t pud,
+               unsigned int nr)
 {
+       unsigned long stride = PUD_SIZE >> PAGE_SHIFT;
+       unsigned int i;
+
        if (&init_mm == mm)
                return;
 
-       __page_table_check_pud_clear(mm, *pudp);
-       if (pud_user_accessible_page(pud)) {
-               page_table_check_set(pud_pfn(pud), PUD_SIZE >> PAGE_SHIFT,
-                                    pud_write(pud));
-       }
+       for (i = 0; i < nr; i++)
+               __page_table_check_pud_clear(mm, *(pudp + i));
+       if (pud_user_accessible_page(pud))
+               page_table_check_set(pud_pfn(pud), stride * nr, pud_write(pud));
 }
-EXPORT_SYMBOL(__page_table_check_pud_set);
+EXPORT_SYMBOL(__page_table_check_puds_set);
 
 void __page_table_check_pte_clear_range(struct mm_struct *mm,
                                        unsigned long addr,