[RFC PATCH 10/34] x86: mm: carve out the generic compile-time folded pgtable case in effective_prot()

Yeoreum Yun yeoreum.yun at arm.com
Thu Jul 16 01:47:43 PDT 2026


On Wed, Jul 15, 2026 at 11:44:51AM +0200, David Hildenbrand (Arm) wrote:
> On 7/14/26 19:58, Yeoreum Yun wrote:
> > On Tue, Jul 14, 2026 at 07:29:38PM +0200, David Hildenbrand (Arm) wrote:
> >> On 7/14/26 18:51, Yeoreum Yun wrote:
> >>>
> >>> Furthermore, the effective_prot() need to require to identify whether
> >>> it's the first pgtable to prevent the inheriting from dummy value.
> >>> So I think it seems to make a ptdump_pt_level_first() like:
> >>>
> >>> diff --git a/mm/ptdump.c b/mm/ptdump.c
> >>> index 973020000096c..2ec5700e4be5e 100644
> >>> --- a/mm/ptdump.c
> >>> +++ b/mm/ptdump.c
> >>> @@ -190,6 +190,23 @@ void ptdump_walk_pgd(struct ptdump_state *st, struct mm_struct *mm, pgd_t *pgd)
> >>>         st->note_page_flush(st);
> >>>  }
> >>>
> >>> +bool pdtump_pt_level_first(struct mm_struct *mm, int level)
> >>> +{
> >>> +       if (!mm || level > CONFIG_PGTABLE_LEVELS)
> >>> +               return false;
> >>
> >> Do we actually ever get !mm ?
> > 
> > Yes. for the case of s390 use mm anyway for folded check.
> That's not what I meant, let me clarify.
> 
> I think in ptdump_walk_pgd() it is guaranteed that mm != NULL, so I am wondering
> why you are handling mm == NULL.

Agree. I'll remove it.
BTW, this helper is incorrect because it returns true even for folded
upper-level page tables. For example, if p4d is folded,
level 0 would still be treated as the first level.

So, it would better to the following:

diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c
index 2afa7a23340e9..4e545988953a0 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 240bd3bff18dd..26fa624eac44e 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 973020000096c..b1d06ac4c0555 100644
--- a/mm/ptdump.c
+++ b/mm/ptdump.c
@@ -190,6 +190,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;
+}
+

-- 
Sincerely,
Yeoreum Yun



More information about the kvm-riscv mailing list