arm64/mm: move __check_safe_pte_update()

Patch series "arm64/mm: Standardize printing for pgtable entries", v3.

Standardize printing for pgtable entries using recently introduced generic
helper ptval_bytes_to_hex_str() in core MM which automatically enables 128
bits entries when added later.

But first move __check_safe_pte_update() outside <asm/pgtable.h> to avoid
a cyclic dependency while accessing these afore mentioned core MM helpers
defined in <linux/pgtable.h>.  This replaces the original page table entry
print standardisation proposal which was part of the D128 series [1].


This patch (of 2):

The page table entry print helpers and related macros which are defined in
<linux/pgtable.h> will not be accessible in platform <asm/pgtable.h> which
is basically caused by cycling dependency.

Move __check_safe_pte_update() inside arch/arm64/mm/mmu.c as a preparation
for subsequent usage of the afore mentioned generic MM helpers.  While
here drop IS_ENABLED(CONFIG_DEBUG_VM), although wrap
__check_safe_pte_update() inside #ifdef CONFIG_DEBUG_VM that preserves the
current code optimization which is achieved via the static inline
functions.

This does not cause any functional change.

[david@kernel.org: aarch64-linux-ld error]
  Link: https://lore.kernel.org/99023678-fd8a-4eef-8e43-a07b504e3e96@kernel.org
Link: https://lore.kernel.org/20260916044933.2689426-2-anshuman.khandual@arm.com
Link: https://lore.kernel.org/linux-mm/20260729122452.3797443-11-anshuman.khandual@arm.com/ [1]
Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
This commit is contained in:
Anshuman Khandual 2026-09-16 10:19:32 +05:30 committed by Andrew Morton
parent 7c7180be97
commit b32f336987
2 changed files with 49 additions and 44 deletions

View File

@ -387,52 +387,13 @@ static inline pte_t __ptep_get(pte_t *ptep)
extern void __sync_icache_dcache(pte_t pteval);
bool pgattr_change_is_safe(pteval_t old, pteval_t new);
/*
* PTE bits configuration in the presence of hardware Dirty Bit Management
* (PTE_WRITE == PTE_DBM):
*
* Dirty Writable | PTE_RDONLY PTE_WRITE PTE_DIRTY (sw)
* 0 0 | 1 0 0
* 0 1 | 1 1 0
* 1 0 | 1 0 1
* 1 1 | 0 1 x
*
* When hardware DBM is not present, the software PTE_DIRTY bit is updated via
* the page fault mechanism. Checking the dirty status of a pte becomes:
*
* PTE_DIRTY || (PTE_WRITE && !PTE_RDONLY)
*/
static inline void __check_safe_pte_update(struct mm_struct *mm, pte_t *ptep,
pte_t pte)
#ifdef CONFIG_DEBUG_VM
void __check_safe_pte_update(struct mm_struct *mm, pte_t *ptep, pte_t pte);
#else
static inline void __check_safe_pte_update(struct mm_struct *mm, pte_t *ptep, pte_t pte)
{
pte_t old_pte;
if (!IS_ENABLED(CONFIG_DEBUG_VM))
return;
old_pte = __ptep_get(ptep);
if (!pte_valid(old_pte) || !pte_valid(pte))
return;
if (mm != current->active_mm && atomic_read(&mm->mm_users) <= 1)
return;
/*
* Check for potential race with hardware updates of the pte
* (__ptep_set_access_flags safely changes valid ptes without going
* through an invalid entry).
*/
VM_WARN_ONCE(!pte_young(pte),
"%s: racy access flag clearing: 0x%016llx -> 0x%016llx",
__func__, pte_val(old_pte), pte_val(pte));
VM_WARN_ONCE(pte_write(old_pte) && !pte_dirty(pte),
"%s: racy dirty state clearing: 0x%016llx -> 0x%016llx",
__func__, pte_val(old_pte), pte_val(pte));
VM_WARN_ONCE(!pgattr_change_is_safe(pte_val(old_pte), pte_val(pte)),
"%s: unsafe attribute change: 0x%016llx -> 0x%016llx",
__func__, pte_val(old_pte), pte_val(pte));
}
#endif /* CONFIG_DEBUG_VM */
static inline void __sync_cache_and_tags(pte_t pte, unsigned int nr_pages)
{

View File

@ -2393,3 +2393,47 @@ int arch_set_user_pkey_access(int pkey, unsigned long init_val)
return 0;
}
#endif
/*
* PTE bits configuration in the presence of hardware Dirty Bit Management
* (PTE_WRITE == PTE_DBM):
*
* Dirty Writable | PTE_RDONLY PTE_WRITE PTE_DIRTY (sw)
* 0 0 | 1 0 0
* 0 1 | 1 1 0
* 1 0 | 1 0 1
* 1 1 | 0 1 x
*
* When hardware DBM is not present, the software PTE_DIRTY bit is updated via
* the page fault mechanism. Checking the dirty status of a pte becomes:
*
* PTE_DIRTY || (PTE_WRITE && !PTE_RDONLY)
*/
#ifdef CONFIG_DEBUG_VM
void __check_safe_pte_update(struct mm_struct *mm, pte_t *ptep, pte_t pte)
{
pte_t old_pte;
old_pte = __ptep_get(ptep);
if (!pte_valid(old_pte) || !pte_valid(pte))
return;
if (mm != current->active_mm && atomic_read(&mm->mm_users) <= 1)
return;
/*
* Check for potential race with hardware updates of the pte
* (__ptep_set_access_flags safely changes valid ptes without going
* through an invalid entry).
*/
VM_WARN_ONCE(!pte_young(pte),
"%s: racy access flag clearing: 0x%016llx -> 0x%016llx",
__func__, pte_val(old_pte), pte_val(pte));
VM_WARN_ONCE(pte_write(old_pte) && !pte_dirty(pte),
"%s: racy dirty state clearing: 0x%016llx -> 0x%016llx",
__func__, pte_val(old_pte), pte_val(pte));
VM_WARN_ONCE(!pgattr_change_is_safe(pte_val(old_pte), pte_val(pte)),
"%s: unsafe attribute change: 0x%016llx -> 0x%016llx",
__func__, pte_val(old_pte), pte_val(pte));
}
#endif /* CONFIG_DEBUG_VM */