[PATCH RFC v2 13/20] x86: mm: carve out the generic compile-time folded pgtable case in effective_prot()
From: Yeoreum Yun
Date: Wed Jul 22 2026 - 11:44:34 EST
From: "David Hildenbrand (Arm)" <david@xxxxxxxxxx>
The behaviour of pXdp_get() will change with generic compile-time folded
page tables. To prepare for that, rework effective_prot() to ignore any
folded page tables entries, as it will unconditionally get called by
ptdump core with pXd_val(pXdp_get()), and we really should be ignoring
that value for folded entries.
For this, introduce ptdump_pt_level_first() to identify the first real
page-table level and update effective_prot with higher_prot only
when the current entry is not folded nor the first level.
There should be no functional change.
Signed-off-by: Yeoreum Yun <yeoreum.yun@xxxxxxx>
---
arch/x86/mm/dump_pagetables.c | 5 ++++-
include/linux/ptdump.h | 1 +
mm/ptdump.c | 11 +++++++++++
3 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c
index 2afa7a23340e..4e545988953a 100644
--- a/arch/x86/mm/dump_pagetables.c
+++ b/arch/x86/mm/dump_pagetables.c
@@ -27,6 +27,7 @@
*/
struct pg_state {
struct ptdump_state ptdump;
+ int first_level;
int level;
pgprotval_t current_prot;
pgprotval_t effective_prot;
@@ -254,7 +255,7 @@ static void effective_prot(struct ptdump_state *pt_st, int level, u64 val)
pgprotval_t prot = val & PTE_FLAGS_MASK;
pgprotval_t effective;
- if (level > 0) {
+ if (level > st->first_level) {
pgprotval_t higher_prot = st->prot_levels[level - 1];
effective = (higher_prot & prot & (_PAGE_USER | _PAGE_RW)) |
@@ -455,6 +456,8 @@ bool ptdump_walk_pgd_level_core(struct seq_file *m,
.seq = m
};
+ st.first_level = ptdump_pt_level_first(mm);
+
ptdump_walk_pgd(&st.ptdump, mm, pgd);
if (!checkwx)
diff --git a/include/linux/ptdump.h b/include/linux/ptdump.h
index 240bd3bff18d..26fa624eac44 100644
--- a/include/linux/ptdump.h
+++ b/include/linux/ptdump.h
@@ -29,6 +29,7 @@ bool ptdump_walk_pgd_level_core(struct seq_file *m,
struct mm_struct *mm, pgd_t *pgd,
bool checkwx, bool dmesg);
void ptdump_walk_pgd(struct ptdump_state *st, struct mm_struct *mm, pgd_t *pgd);
+int ptdump_pt_level_first(struct mm_struct *mm);
bool ptdump_check_wx(void);
static inline void debug_checkwx(void)
diff --git a/mm/ptdump.c b/mm/ptdump.c
index 5851096e6f65..96676c90430f 100644
--- a/mm/ptdump.c
+++ b/mm/ptdump.c
@@ -197,6 +197,17 @@ void ptdump_walk_pgd(struct ptdump_state *st, struct mm_struct *mm, pgd_t *pgd)
st->note_page_flush(st);
}
+int ptdump_pt_level_first(struct mm_struct *mm)
+{
+ if (mm_pmd_folded(mm))
+ return 3;
+ if (mm_pud_folded(mm))
+ return 2;
+ if (mm_p4d_folded(mm))
+ return 1;
+ return 0;
+}
+
static int check_wx_show(struct seq_file *m, void *v)
{
if (ptdump_check_wx())
--
2.43.0