Commit 91e40668 authored by Ryan Roberts's avatar Ryan Roberts Committed by Will Deacon
Browse files

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: default avatarAnshuman Khandual <anshuman.khandual@arm.com>
Reviewed-by: default avatarPasha Tatashin <pasha.tatashin@soleen.com>
Reviewed-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Signed-off-by: default avatarRyan Roberts <ryan.roberts@arm.com>
Tested-by: default avatarLuiz Capitulino <luizcap@redhat.com>
Link: https://lore.kernel.org/r/20250422081822.1836315-4-ryan.roberts@arm.com


Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent 5b3f8917
Loading
Loading
Loading
Loading
+18 −12
Original line number Diff line number Diff line
@@ -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 */
+20 −14
Original line number Diff line number Diff line
@@ -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,