mm/page_table_check: Batch-check pmds/puds just like ptes

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>
This commit is contained in:
Ryan Roberts 2025-04-22 09:18:11 +01:00 committed by Will Deacon
parent 5b3f891764
commit 91e40668e7
2 changed files with 38 additions and 26 deletions

View 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_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, void __page_table_check_ptes_set(struct mm_struct *mm, pte_t *ptep, pte_t pte,
unsigned int nr); unsigned int nr);
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,
void __page_table_check_pud_set(struct mm_struct *mm, pud_t *pudp, pud_t pud); 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, void __page_table_check_pte_clear_range(struct mm_struct *mm,
unsigned long addr, unsigned long addr,
pmd_t pmd); 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); __page_table_check_ptes_set(mm, ptep, pte, nr);
} }
static inline void page_table_check_pmd_set(struct mm_struct *mm, pmd_t *pmdp, static inline void page_table_check_pmds_set(struct mm_struct *mm,
pmd_t pmd) pmd_t *pmdp, pmd_t pmd, unsigned int nr)
{ {
if (static_branch_likely(&page_table_check_disabled)) if (static_branch_likely(&page_table_check_disabled))
return; 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, static inline void page_table_check_puds_set(struct mm_struct *mm,
pud_t pud) pud_t *pudp, pud_t pud, unsigned int nr)
{ {
if (static_branch_likely(&page_table_check_disabled)) if (static_branch_likely(&page_table_check_disabled))
return; 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, 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, static inline void page_table_check_pmds_set(struct mm_struct *mm,
pmd_t pmd) pmd_t *pmdp, pmd_t pmd, unsigned int nr)
{ {
} }
static inline void page_table_check_pud_set(struct mm_struct *mm, pud_t *pudp, static inline void page_table_check_puds_set(struct mm_struct *mm,
pud_t pud) 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 */ #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 */ #endif /* __LINUX_PAGE_TABLE_CHECK_H */

View 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))); 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) if (&init_mm == mm)
return; return;
page_table_check_pmd_flags(pmd); page_table_check_pmd_flags(pmd);
__page_table_check_pmd_clear(mm, *pmdp); for (i = 0; i < nr; i++)
if (pmd_user_accessible_page(pmd)) { __page_table_check_pmd_clear(mm, *(pmdp + i));
page_table_check_set(pmd_pfn(pmd), PMD_SIZE >> PAGE_SHIFT, if (pmd_user_accessible_page(pmd))
pmd_write(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) if (&init_mm == mm)
return; return;
__page_table_check_pud_clear(mm, *pudp); for (i = 0; i < nr; i++)
if (pud_user_accessible_page(pud)) { __page_table_check_pud_clear(mm, *(pudp + i));
page_table_check_set(pud_pfn(pud), PUD_SIZE >> PAGE_SHIFT, if (pud_user_accessible_page(pud))
pud_write(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, void __page_table_check_pte_clear_range(struct mm_struct *mm,
unsigned long addr, unsigned long addr,