* [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable
@ 2026-09-21 10:55 Yeoreum Yun
2026-09-21 10:55 ` [PATCH 01/21] ARM: mm: make nommu pgd_t a scalar Yeoreum Yun
` (21 more replies)
0 siblings, 22 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc, Muhammad Usama Anjum, Yeoreum Yun, Sohil Mehta
Using ptep_get() and its counterparts in common code is suboptimal on
kernel configurations with generic compile-time folded page tables.
By default, ptep_get() and its friends expands to READ_ONCE(),
forcing the compiler to emit a load even when the value is not used afterwards.
This issue was recently reported by Christophe Leroy [1] for ppc32
preventing futher code conversion to ptep_get()/pmdp_get()/... helper
and the same behavior can also be observed on arm64 when built with
2- or 3-level page tables
e.g) perf_get_page_size() in arm64 with CONFIG_PGTABLE_LEVEL=3:
00000000000052a0 <perf_get_page_size>:
...
52dc: d53b4234 mrs x20, DAIF
52e0: d50343df msr DAIFSet, #0x3
...
52fc: d35e9a69 ubfx x9, x19, #30, #9 /* pud_offset_lockless() */
5300: f9403508 ldr x8, [x8, #0x68]
5304: f869790a ldr x10, [x8, x9, lsl #3] /* pudp_get() */
5308: f90007ea str x10, [sp, #0x8]
530c: f8697908 ldr x8, [x8, x9, lsl #3] /* pudp_get() */
...
5360: 90000009 adrp x9, 0x5000 <perf_prepare_sample+0x548>
5364: 92746908 and x8, x8, #0x7ffffff000
5368: d3557675 ubfx x21, x19, #21, #9 /* pmd_offset_lockless() */
...
5394: f8757ac8 ldr x8, [x22, x21, lsl #3] /* pmdp_get() */
Though PGTABLE_LEVEL=3, since the pudp_get() still remain with
READ_ONCE(), there's redundant load for the pud which is folded.
To prevent generating suboptimal code, make pXdp_get() return a dummy
entry for compile-time folded page tables, make the helpers such as
pXd_offset()/pXd_offset_lockless(), set_pXd() validate dummy entries
at compile time to catch the wrong usage and prohibit calls to
pXd_page() in pgtable-nopXd.h.
This series does not change the behaviour of existing code that directly
manipulates folded page-table levels using set_pgd(), pgd_page_vaddr(), and
related helpers. Those helpers continue to behave as before.
The new restrictions only apply to code that adopts the pXdp_get()-based
access model for compile-time folded page tables.
As the pXdp_get() can return *dummy* entry, some of code using
the stack value where saves the pXdp_get() could be a problematic:
1. Passing address of stack value where saves the pXdp_get() result
to pXd_offset() for example:
pud_t *pudp, pud;
pmd_t *pmdp;
pud = pudp_get(pudp, address);
pmdp = pmd_offset(&pud, pud, address);
(e.g. host_pfn_mapping_level() in loongarch).
2. Using the pXdp_get() result to use as argument of pXd_val() and
to check prot without checking pgtable is folded.
for example, x86's effective_prot().
3. Using set_pXd() with pXdp_get() will set problematic dummy entry
in folded page table like:
set_pXd(pxdp, pXdp_get(pxdp_k));
4. Using pgd_page_vaddr() to get the first-level pgtable.
passing dummy pxdp_get() for pgd_page_vaddr() will return wrong
address. Therefore, make pgd_page_vaddr() and pXd_pgtable() to
trigger the error for improper usage with folded dummy entry in the
generic compile-time folded pgtable.
Thanksfully, above cases are rare since (1) most of usage using
pXd_offset() with result of upper pXd_offset(), (2) it's extreamely
rare to use pXd_val() for non-leaf entry in the kernel,
(3) is to handle the vmalloc_fault or set the first level of page table
and (4) to setup early page table and etc.
Therefore, properly handle this uncommon and problematic pattern, and
document the current design of compile-time folded page tables.
This patch is based on mm-unstable.
Future work
===========
- print_bad_page_map() and show_pte() still prints dummy values
instead of printing the same content for all generic compile-time
folded page tables. We might want to skip printing dummy values later.
- We currently catch abuse of dummy values on the stack at compile-time by
relying on constant propagation by the compiler. Usama's work [3] on using
distinct types for sw vs. hw PTEs could help here as well."
- Clean up vmalloc fault handling by synchronizing the vmalloc entry on
32-bit architectures. This code is almost identical across architectures.
- Unfortunately, the current design of compile-time folded page tables appears
to be internally consistent but confusing. For example,
when CONFIG_PGTABLE_LEVELS is 2, p4d, pud, and pmd are expected to
be folded into pgd. However, the architecture code uses set_pmd()
to update the top-level page-table entry, even though it includes pgtable-nopmd.h.
In the future, it would be good to eliminate this source of confusion,
possibly by treating all folded upper levels consistently as dummy wrappers
around the highest real page-table level:
NOPGD
--> +------+ P4D
| ptr0 |-------> +------+ PUD
+------+ | ptr0 |-------> +-----+
| ptr1 |- | ptr | -------> ...
| ptr2 | \ | ptr |
| ptr3 | \ ...
... \
\ PUD
+----> +-----+
| ptr | -------> ...
| ptr |
...
Link: [1] https://lore.kernel.org/all/0019d675-ce3d-4a5c-89ed-f126c45145c9@kernel.org/
Link: [2] https://lore.kernel.org/all/20251113014656.2605447-1-samuel.holland@sifive.com/
Link: [3] https://lore.kernel.org/r/74182e50-b54f-4d2d-a27f-3a59a538d6bc@arm.com
Patch History
=============
from RFC v3 to v1:
- Drop and rebase for CONFIG_X86_DIRECT_GBPAGES and use the Dave's
patch (https://lore.kernel.org/all/20260902194718.E1FF3041@davehans-spike.ostc.intel.com/)
- Link to RFC v3: https://lore.kernel.org/r/20260902-dummy_ptxp3-v3-0-5d8f5b17c25c@arm.com
from RFC v2 to RFC v3:
- repasre commit message
- move ptdump_pgtable_first_level() into pgalloc.h
- skip the huge pud operation when CONFIG_X86_DIRECT_GBPAGES is disabled
- docuemtns compile-time folded page table
- drop the applied patch.
- Link to RFC v2: https://lore.kernel.org/all/20260722-dummy_ptxp3-v2-0-d9e4bad31e0a@arm.com/
from RFC v1 to RFC v2:
- Restore slient fallback to next pXd in set_pXd() and pXd_pgtable()
and add check whether they're called with dummy entry.
- Add some comment for returning first entry of pgd in arm with
2 pgtable-level
- Link to RFC v1: https://lore.kernel.org/all/20260713135614.1618183-1-yeoreum.yun@arm.com/
---
Dave Hansen (1):
x86/mm: Introduce helper for checking direct map 1G page support
David Hildenbrand (Arm) (13):
ARM: mm: make nommu pgd_t a scalar
ARM: mm: make 2-level pgd_t a scalar
ARM: mm: remove custom pgdp_get()
LoongArch: mm: define pud_leaf() only when PUD exists
MIPS: mm: define pud_leaf() only when PUD exists
mm/pgtable: define (pgd|p4d|pud)_leaf() for folded page tables
mm/pgtable: define (pgd|p4d|pud)_offset_lockless() for folded page tables
openrisc/pgtable: drop __pmd_offset()
mm/pgtable: optimize pmdp_get() and friends for folded pagetable levels
mm/pgtable: catch abuse of folded dummy pgd_t/p4d_t/pud_t
mm/pgtable: disallow calling (pgd|p4d|pud)_page, pgd_page_vaddr() and (p4d|pud)_pgtable with dummy
mm/pgtable: disallow calling folded set_pgd/set_p4d/set_pud with dummy
Documentation: mm: clarify behaviour of compile-time folded page tables
Yeoreum Yun (7):
mm: vmscan: remove stack copy address of pud/pmd pass in walk_pud/pmd_range()
loongarch: kvm: remove stack copy address of pXd in pXd_offset()
riscv: kvm: remove stack copy address of pXd in pXd_offset()
riscv: mm: use proper set_pXd() for generic compile-time folded patable in vmalloc_fault()
mm/pgtable: redefine PGTABLE_LEVEL enum with ascend order from PGD
x86: mm: use pgtable_level enum in effective_prot_pXd()
x86: mm: carve out the generic compile-time folded pgtable case in effective_prot()
Documentation/mm/page_tables.rst | 84 +++++++++++++++++++++++++----
arch/arm/include/asm/page-nommu.h | 4 +-
arch/arm/include/asm/pgtable-2level-types.h | 20 +++++--
arch/arm/include/asm/pgtable.h | 2 -
arch/arm64/include/asm/pgtable.h | 23 --------
arch/loongarch/include/asm/pgtable.h | 2 +
arch/loongarch/kvm/mmu.c | 20 ++++---
arch/mips/include/asm/pgtable.h | 2 +
arch/openrisc/include/asm/pgtable.h | 3 --
arch/riscv/kvm/mmu.c | 20 ++++---
arch/riscv/mm/fault.c | 52 +++++++++++-------
arch/x86/include/asm/pgtable.h | 14 +++++
arch/x86/kernel/cpu/common.c | 2 +-
arch/x86/kernel/machine_kexec_64.c | 2 +-
arch/x86/mm/dump_pagetables.c | 18 ++++---
arch/x86/mm/init.c | 2 +-
arch/x86/mm/pat/set_memory.c | 6 +--
include/asm-generic/pgtable-nop4d.h | 54 +++++++++++++++----
include/asm-generic/pgtable-nopmd.h | 54 +++++++++++++++----
include/asm-generic/pgtable-nopud.h | 56 +++++++++++++++----
include/linux/pgtable.h | 69 +++++++++++++++++-------
mm/vmscan.c | 4 +-
22 files changed, 371 insertions(+), 142 deletions(-)
---
base-commit: 8d61431ed2607386b427752505379536eb634ce8
change-id: 20260722-dummy_ptxp3-3741d78cc70f
Best regards,
--
Sincerely,
Yeoreum Yun
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 01/21] ARM: mm: make nommu pgd_t a scalar
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 02/21] ARM: mm: make 2-level " Yeoreum Yun
` (20 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc
From: "David Hildenbrand (Arm)" <david@kernel.org>
As pgd_t is returned from a function, like pgdp_get(). pgd_t shouldn't be
an array.
There is no need to match the actual arm page tables, because with nommu
there are no page tables. It's all just in place to make the compiler
happy. Making it a scalar will make the compiler happy.
So let's just use an u32.
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
arch/arm/include/asm/page-nommu.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/include/asm/page-nommu.h b/arch/arm/include/asm/page-nommu.h
index e74415c959bea..88659b38e2364 100644
--- a/arch/arm/include/asm/page-nommu.h
+++ b/arch/arm/include/asm/page-nommu.h
@@ -18,12 +18,12 @@
*/
typedef unsigned long pte_t;
typedef unsigned long pmd_t;
-typedef unsigned long pgd_t[2];
+typedef unsigned long pgd_t;
typedef unsigned long pgprot_t;
#define pte_val(x) (x)
#define pmd_val(x) (x)
-#define pgd_val(x) ((x)[0])
+#define pgd_val(x) (x)
#define pgprot_val(x) (x)
#define __pte(x) (x)
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 02/21] ARM: mm: make 2-level pgd_t a scalar
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
2026-09-21 10:55 ` [PATCH 01/21] ARM: mm: make nommu pgd_t a scalar Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 03/21] ARM: mm: remove custom pgdp_get() Yeoreum Yun
` (19 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc
From: "David Hildenbrand (Arm)" <david@kernel.org>
As pgd_t is returned from a function like pgdp_get(), pgd_t shouldn't
be an array.
So, just use an u64, and extract the right 32bit value in pgd_val().
Leave the STRICT_MM_TYPECHECKS case alone for now.
As an alternative, the STRICT_MM_TYPECHECKS approach could be used here
as well, but using an u64 looks conceptually cleaner, even though
pgd_val() gets a bit more involved.
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
arch/arm/include/asm/pgtable-2level-types.h | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/arch/arm/include/asm/pgtable-2level-types.h b/arch/arm/include/asm/pgtable-2level-types.h
index 650e793f41429..805044ea315b7 100644
--- a/arch/arm/include/asm/pgtable-2level-types.h
+++ b/arch/arm/include/asm/pgtable-2level-types.h
@@ -25,7 +25,7 @@ typedef struct { pteval_t pgprot; } pgprot_t;
#define pte_val(x) ((x).pte)
#define pmd_val(x) ((x).pmd)
-#define pgd_val(x) ((x).pgd[0])
+#define pgd_val(x) ((x).pgd[0])
#define pgprot_val(x) ((x).pgprot)
#define __pte(x) ((pte_t) { (x) } )
@@ -36,14 +36,28 @@ typedef struct { pteval_t pgprot; } pgprot_t;
/*
* .. while these make it easier on the compiler
*/
+typedef u64 pgdval_t;
+
typedef pteval_t pte_t;
typedef pmdval_t pmd_t;
-typedef pmdval_t pgd_t[2];
+typedef pgdval_t pgd_t;
typedef pteval_t pgprot_t;
#define pte_val(x) (x)
#define pmd_val(x) (x)
-#define pgd_val(x) ((x)[0])
+
+static inline pmdval_t pgd_val(pgd_t pgd)
+{
+ /*
+ * A PGD entry actually corresponds to two PMD entries in the PMD table.
+ * Both PMD entries point to PTE tables residing in the same physical page,
+ * but at different offsets. See include/asm/pgtable-2level.h for details.
+ *
+ * Historically, pgd_val() has returned the lower of the two PMD entries.
+ */
+ return (*(pmdval_t (*)[2])&pgd)[0];
+}
+
#define pgprot_val(x) (x)
#define __pte(x) (x)
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 03/21] ARM: mm: remove custom pgdp_get()
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
2026-09-21 10:55 ` [PATCH 01/21] ARM: mm: make nommu pgd_t a scalar Yeoreum Yun
2026-09-21 10:55 ` [PATCH 02/21] ARM: mm: make 2-level " Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 04/21] LoongArch: mm: define pud_leaf() only when PUD exists Yeoreum Yun
` (18 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc
From: "David Hildenbrand (Arm)" <david@kernel.org>
Now that pgd_t is no longer an array and rely on the common
code pgdp_get(), which is a static inline function that returns pgd_t.
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
arch/arm/include/asm/pgtable.h | 2 --
1 file changed, 2 deletions(-)
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 8dd17d20faa33..ff3868acea945 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -134,8 +134,6 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
-#define pgdp_get(pgpd) READ_ONCE(*pgdp)
-
#define pud_page(pud) pmd_page(__pmd(pud_val(pud)))
#define pud_write(pud) pmd_write(__pmd(pud_val(pud)))
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 04/21] LoongArch: mm: define pud_leaf() only when PUD exists
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (2 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 03/21] ARM: mm: remove custom pgdp_get() Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 05/21] MIPS: " Yeoreum Yun
` (17 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc
From: "David Hildenbrand (Arm)" <david@kernel.org>
In include/asm-generic/pgtable-nopmd.h, pud_leaf() is hardcoded
to return false as inline function, but it misses the "define pud_leaf
pud_leaf" part.
To prepare for fixing that, define pud_leaf() only when
__PAGETABLE_PMD_FOLDED isn't defined.
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
arch/loongarch/include/asm/pgtable.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/loongarch/include/asm/pgtable.h b/arch/loongarch/include/asm/pgtable.h
index cf29a4c8ac593..8aee4fc27a26e 100644
--- a/arch/loongarch/include/asm/pgtable.h
+++ b/arch/loongarch/include/asm/pgtable.h
@@ -630,7 +630,9 @@ static inline long pmd_protnone(pmd_t pmd)
#endif /* CONFIG_ARCH_HAS_PTE_PROTNONE */
#define pmd_leaf(pmd) ((pmd_val(pmd) & _PAGE_HUGE) != 0)
+#ifndef __PAGETABLE_PMD_FOLDED
#define pud_leaf(pud) ((pud_val(pud) & _PAGE_HUGE) != 0)
+#endif
/*
* We provide our own get_unmapped area to cope with the virtual aliasing
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 05/21] MIPS: mm: define pud_leaf() only when PUD exists
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (3 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 04/21] LoongArch: mm: define pud_leaf() only when PUD exists Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 06/21] mm/pgtable: define (pgd|p4d|pud)_leaf() for folded page tables Yeoreum Yun
` (16 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc
From: "David Hildenbrand (Arm)" <david@kernel.org>
In include/asm-generic/pgtable-nopmd.h, pud_leaf() has hardcoded
to return false as inline function, but it misses the "define pud_leaf"
part.
To prepare for fixing that, define pud_leaf() only when
__PAGETABLE_PMD_FOLDED isn't defined.
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
arch/mips/include/asm/pgtable.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
index fa7b935f947ca..151f4d15bd12b 100644
--- a/arch/mips/include/asm/pgtable.h
+++ b/arch/mips/include/asm/pgtable.h
@@ -745,8 +745,10 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
#ifdef _PAGE_HUGE
#define pmd_leaf(pmd) ((pmd_val(pmd) & _PAGE_HUGE) != 0)
+#ifndef __PAGETABLE_PMD_FOLDED
#define pud_leaf(pud) ((pud_val(pud) & _PAGE_HUGE) != 0)
#endif
+#endif
#define gup_fast_permitted(start, end) (!cpu_has_dc_aliases)
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 06/21] mm/pgtable: define (pgd|p4d|pud)_leaf() for folded page tables
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (4 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 05/21] MIPS: " Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 07/21] mm/pgtable: define (pgd|p4d|pud)_offset_lockless() " Yeoreum Yun
` (15 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc
From: "David Hildenbrand (Arm)" <david@kernel.org>
Define (pgd|p4d|pud)_leaf(), hard-coding it to "false". Note
that it's missed to define pud_leaf() before, allowing architectures to
unknowingly overwrite it.
Still use static inline functions (type checking), and while at it, just
use "bool" as a return value.
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
include/asm-generic/pgtable-nop4d.h | 3 +++
include/asm-generic/pgtable-nopmd.h | 3 ++-
include/asm-generic/pgtable-nopud.h | 3 +++
3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/include/asm-generic/pgtable-nop4d.h b/include/asm-generic/pgtable-nop4d.h
index 1cf739ee38aa1..c6a5a43899b50 100644
--- a/include/asm-generic/pgtable-nop4d.h
+++ b/include/asm-generic/pgtable-nop4d.h
@@ -22,6 +22,9 @@ static inline int pgd_none(pgd_t pgd) { return 0; }
static inline int pgd_bad(pgd_t pgd) { return 0; }
static inline int pgd_present(pgd_t pgd) { return 1; }
static inline void pgd_clear(pgd_t *pgd) { }
+static inline bool pgd_leaf(pgd_t pgd) { return false; }
+#define pgd_leaf pgd_leaf
+#define p4d_ERROR(p4d) (pgd_ERROR((p4d).pgd))
#define pgd_populate(mm, pgd, p4d) do { } while (0)
#define pgd_populate_safe(mm, pgd, p4d) do { } while (0)
diff --git a/include/asm-generic/pgtable-nopmd.h b/include/asm-generic/pgtable-nopmd.h
index ff4235cf84d77..4e5aaf253b6a5 100644
--- a/include/asm-generic/pgtable-nopmd.h
+++ b/include/asm-generic/pgtable-nopmd.h
@@ -31,7 +31,8 @@ static inline int pud_none(pud_t pud) { return 0; }
static inline int pud_bad(pud_t pud) { return 0; }
static inline int pud_present(pud_t pud) { return 1; }
static inline int pud_user(pud_t pud) { return 0; }
-static inline int pud_leaf(pud_t pud) { return 0; }
+static inline bool pud_leaf(pud_t pud) { return false; }
+#define pud_leaf pud_leaf
static inline void pud_clear(pud_t *pud) { }
#define pud_populate(mm, pmd, pte) do { } while (0)
diff --git a/include/asm-generic/pgtable-nopud.h b/include/asm-generic/pgtable-nopud.h
index eedee8e3ad68f..6c9bca78047c4 100644
--- a/include/asm-generic/pgtable-nopud.h
+++ b/include/asm-generic/pgtable-nopud.h
@@ -29,6 +29,9 @@ static inline int p4d_none(p4d_t p4d) { return 0; }
static inline int p4d_bad(p4d_t p4d) { return 0; }
static inline int p4d_present(p4d_t p4d) { return 1; }
static inline void p4d_clear(p4d_t *p4d) { }
+static inline bool p4d_leaf(p4d_t p4d) { return false; }
+#define p4d_leaf p4d_leaf
+#define pud_ERROR(pud) (p4d_ERROR((pud).p4d))
#define p4d_populate(mm, p4d, pud) do { } while (0)
#define p4d_populate_safe(mm, p4d, pud) do { } while (0)
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 07/21] mm/pgtable: define (pgd|p4d|pud)_offset_lockless() for folded page tables
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (5 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 06/21] mm/pgtable: define (pgd|p4d|pud)_leaf() for folded page tables Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 08/21] mm: vmscan: remove stack copy address of pud/pmd pass in walk_pud/pmd_range() Yeoreum Yun
` (14 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc
From: "David Hildenbrand (Arm)" <david@kernel.org>
The default helpers fallback to pud_offset(), passing a pointer to the
stack value.
Let's provide variants that do exactly what (pgd|p4d|pud)_offset() do,
but ignore the passed pgd_t/p4d_t/pud_t, consequently not working on a
pointer to the stack value like the default handlers would.
With this patch, Drop the arm64 custom variant that did that. As it documents:
Note: reusing the original pointer means that it may be
dereferenced the same (live) page-table entry multiple times.
This is safe because it is still only loaded once in the
context of each level and the CPU guarantees same-address
read-after-read ordering.
Do not document this, as the double read will be removed in the next patch.
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
arch/arm64/include/asm/pgtable.h | 23 -----------------------
include/asm-generic/pgtable-nop4d.h | 7 +++++++
include/asm-generic/pgtable-nopmd.h | 7 +++++++
include/asm-generic/pgtable-nopud.h | 7 +++++++
4 files changed, 21 insertions(+), 23 deletions(-)
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index e89ec5f4787b4..a3c882e46777a 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -1180,29 +1180,6 @@ static inline bool pgtable_l5_enabled(void) { return false; }
#define p4d_clear_fixmap()
#define p4d_offset_kimg(dir,addr) ((p4d_t *)dir)
-
-static inline
-p4d_t *p4d_offset_lockless_folded(pgd_t *pgdp, pgd_t pgd, unsigned long addr)
-{
- /*
- * With runtime folding of the pud, pud_offset_lockless() passes
- * the 'pgd_t *' we return here to p4d_to_folded_pud(), which
- * will offset the pointer assuming that it points into
- * a page-table page. However, the fast GUP path passes us a
- * pgd_t allocated on the stack and so we must use the original
- * pointer in 'pgdp' to construct the p4d pointer instead of
- * using the generic p4d_offset_lockless() implementation.
- *
- * Note: reusing the original pointer means that we may
- * dereference the same (live) page-table entry multiple times.
- * This is safe because it is still only loaded once in the
- * context of each level and the CPU guarantees same-address
- * read-after-read ordering.
- */
- return p4d_offset(pgdp, addr);
-}
-#define p4d_offset_lockless p4d_offset_lockless_folded
-
#endif /* CONFIG_PGTABLE_LEVELS > 4 */
#define pgd_set_fixmap(addr) ((pgd_t *)set_fixmap_offset(FIX_PGD, addr))
diff --git a/include/asm-generic/pgtable-nop4d.h b/include/asm-generic/pgtable-nop4d.h
index c6a5a43899b50..019c3f074b771 100644
--- a/include/asm-generic/pgtable-nop4d.h
+++ b/include/asm-generic/pgtable-nop4d.h
@@ -39,6 +39,13 @@ static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address)
return (p4d_t *)pgd;
}
+static inline p4d_t *p4d_offset_lockless(pgd_t *pgdp, pgd_t pgd,
+ unsigned long address)
+{
+ return (p4d_t *)pgdp;
+}
+#define p4d_offset_lockless p4d_offset_lockless
+
#define p4d_val(x) (pgd_val((x).pgd))
#define __p4d(x) ((p4d_t) { __pgd(x) })
diff --git a/include/asm-generic/pgtable-nopmd.h b/include/asm-generic/pgtable-nopmd.h
index 4e5aaf253b6a5..1dd5b165234be 100644
--- a/include/asm-generic/pgtable-nopmd.h
+++ b/include/asm-generic/pgtable-nopmd.h
@@ -49,6 +49,13 @@ static inline pmd_t * pmd_offset(pud_t * pud, unsigned long address)
}
#define pmd_offset pmd_offset
+static inline pmd_t *pmd_offset_lockless(pud_t *pudp, pud_t pud,
+ unsigned long address)
+{
+ return (pmd_t *)pudp;
+}
+#define pmd_offset_lockless pmd_offset_lockless
+
#define pmd_val(x) (pud_val((x).pud))
#define __pmd(x) ((pmd_t) { __pud(x) } )
diff --git a/include/asm-generic/pgtable-nopud.h b/include/asm-generic/pgtable-nopud.h
index 6c9bca78047c4..5a2b0a81ae197 100644
--- a/include/asm-generic/pgtable-nopud.h
+++ b/include/asm-generic/pgtable-nopud.h
@@ -47,6 +47,13 @@ static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
}
#define pud_offset pud_offset
+static inline pud_t *pud_offset_lockless(p4d_t *p4dp, p4d_t p4d,
+ unsigned long address)
+{
+ return (pud_t *)p4dp;
+}
+#define pud_offset_lockless pud_offset_lockless
+
#define pud_val(x) (p4d_val((x).p4d))
#define __pud(x) ((pud_t) { __p4d(x) })
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 08/21] mm: vmscan: remove stack copy address of pud/pmd pass in walk_pud/pmd_range()
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (6 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 07/21] mm/pgtable: define (pgd|p4d|pud)_offset_lockless() " Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 09/21] loongarch: kvm: remove stack copy address of pXd in pXd_offset() Yeoreum Yun
` (13 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc, Muhammad Usama Anjum, Yeoreum Yun
The behaviour of pXdp_get() will change with generic compile-time folded
page tables. To prepare for that, replace passing the address of a stack
copy of a pud/pmd to walk_pmd/pte_range() with passing the pud/pmd pointer
directly so that makes allowing folded entries to be ignored and
check the concurrent access proeprly otherwise pXd_same() would return
always true.
There should be no functional change.
Reviewed-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
mm/vmscan.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 836f50814ffae..f771443cd78b6 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -3871,7 +3871,7 @@ static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end,
walk->mm_stats[MM_NONLEAF_FOUND]++;
- if (!walk_pte_range(&val, addr, next, args))
+ if (!walk_pte_range(pmd + i, addr, next, args))
continue;
walk->mm_stats[MM_NONLEAF_ADDED]++;
@@ -3907,7 +3907,7 @@ static int walk_pud_range(p4d_t *p4d, unsigned long start, unsigned long end,
if (!pud_present(val) || WARN_ON_ONCE(pud_leaf(val)))
continue;
- walk_pmd_range(&val, addr, next, args);
+ walk_pmd_range(pud + i, addr, next, args);
if (need_resched() || walk->batched >= MAX_LRU_BATCH) {
end = (addr | ~PUD_MASK) + 1;
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 09/21] loongarch: kvm: remove stack copy address of pXd in pXd_offset()
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (7 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 08/21] mm: vmscan: remove stack copy address of pud/pmd pass in walk_pud/pmd_range() Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 10/21] riscv: " Yeoreum Yun
` (12 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc, Yeoreum Yun
The behaviour of pXdp_get() will change with generic compile-time folded
page tables. To prepare for that, rework host_pfn_mapping_level() to avoid
use of a stack copy of a pXd and pass it as argument to pXd_offset() so that
the folded entries value is ignored.
Replace direct uses of stack-based pXd values with pXd_offset_lockless().
And there should be no functional change.
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
arch/loongarch/kvm/mmu.c | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/arch/loongarch/kvm/mmu.c b/arch/loongarch/kvm/mmu.c
index e104897aa5328..837b40bb694f4 100644
--- a/arch/loongarch/kvm/mmu.c
+++ b/arch/loongarch/kvm/mmu.c
@@ -669,10 +669,10 @@ static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn,
int level = 0;
unsigned long hva;
unsigned long flags;
- pgd_t pgd;
- p4d_t p4d;
- pud_t pud;
- pmd_t pmd;
+ pgd_t *pgdp, pgd;
+ p4d_t *p4dp, p4d;
+ pud_t *pudp, pud;
+ pmd_t *pmdp, pmd;
/*
* Note, using the already-retrieved memslot and __gfn_to_hva_memslot()
@@ -698,19 +698,23 @@ static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn,
* value) and then p*d_offset() walks into the target huge page instead
* of the old page table (sees the new value).
*/
- pgd = pgdp_get(pgd_offset(kvm->mm, hva));
+ pgdp = pgd_offset(kvm->mm, hva);
+ pgd = pgdp_get(pgdp);
if (pgd_none(pgd))
goto out;
- p4d = p4dp_get(p4d_offset(&pgd, hva));
+ p4dp = p4d_offset_lockless(pgdp, pgd, hva);
+ p4d = p4dp_get(p4dp);
if (p4d_none(p4d) || !p4d_present(p4d))
goto out;
- pud = pudp_get(pud_offset(&p4d, hva));
+ pudp = pud_offset_lockless(p4dp, p4d, hva);
+ pud = pudp_get(pudp);
if (pud_none(pud) || !pud_present(pud))
goto out;
- pmd = pmdp_get(pmd_offset(&pud, hva));
+ pmdp = pmd_offset_lockless(pudp, pud, hva);
+ pmd = pmdp_get(pmdp);
if (pmd_none(pmd) || !pmd_present(pmd))
goto out;
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 10/21] riscv: kvm: remove stack copy address of pXd in pXd_offset()
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (8 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 09/21] loongarch: kvm: remove stack copy address of pXd in pXd_offset() Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 11/21] riscv: mm: use proper set_pXd() for generic compile-time folded patable in vmalloc_fault() Yeoreum Yun
` (11 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc, Yeoreum Yun
The behaviour of pXdp_get() will change with generic compile-time folded
page tables. To prepare for that, rework get_hva_mapping_size() to avoid
use of a stack copy of a pXd and pass it as argument to pXd_offset() so that
the folded entries value is ignored.
Replace direct uses of stack-based pXd values with pXd_offset_lockless()
and there should be no functional change.
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
arch/riscv/kvm/mmu.c | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
index 5c5c77f98bf0f..b97224e14fc16 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -450,10 +450,10 @@ static int get_hva_mapping_size(struct kvm *kvm,
{
int size = PAGE_SIZE;
unsigned long flags;
- pgd_t pgd;
- p4d_t p4d;
- pud_t pud;
- pmd_t pmd;
+ pgd_t *pgdp, pgd;
+ p4d_t *p4dp, p4d;
+ pud_t *pudp, pud;
+ pmd_t *pmdp, pmd;
/*
* Disable IRQs to prevent concurrent tear down of host page tables,
@@ -469,15 +469,18 @@ static int get_hva_mapping_size(struct kvm *kvm,
* value) and then p*d_offset() walks into the target huge page instead
* of the old page table (sees the new value).
*/
- pgd = pgdp_get(pgd_offset(kvm->mm, hva));
+ pgdp = pgd_offset(kvm->mm, hva);
+ pgd = pgdp_get(pgdp);
if (pgd_none(pgd))
goto out;
- p4d = p4dp_get(p4d_offset(&pgd, hva));
+ p4dp = p4d_offset_lockless(pgdp, pgd, hva);
+ p4d = p4dp_get(p4dp);
if (p4d_none(p4d) || !p4d_present(p4d))
goto out;
- pud = pudp_get(pud_offset(&p4d, hva));
+ pudp = pud_offset_lockless(p4dp, p4d, hva);
+ pud = pudp_get(pudp);
if (pud_none(pud) || !pud_present(pud))
goto out;
@@ -486,7 +489,8 @@ static int get_hva_mapping_size(struct kvm *kvm,
goto out;
}
- pmd = pmdp_get(pmd_offset(&pud, hva));
+ pmdp = pmd_offset_lockless(pudp, pud, hva);
+ pmd = pmdp_get(pmdp);
if (pmd_none(pmd) || !pmd_present(pmd))
goto out;
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 11/21] riscv: mm: use proper set_pXd() for generic compile-time folded patable in vmalloc_fault()
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (9 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 10/21] riscv: " Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 12/21] mm/pgtable: redefine PGTABLE_LEVEL enum with ascend order from PGD Yeoreum Yun
` (10 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc, Yeoreum Yun
The behaviour of pXdp_get() will change with generic compile-time folded
page tables, making it invalid to use set_pXd() with the result of
pXdp_get(). Instead, the appropriate first-level set_pXd() must be paired
with the corresponding pXdp_get().
Therefore, call the appropriate set_pXd() for generic compile-time folded
page tables so that vmalloc_fault() continues to handle folded entries
correctly when checking pXd_present().
There should be no functional change.
Since most architectures use a similar pattern to handle vmalloc fault
by syncing the faulted entry, it would be worth cleaning this up by
introducing a common helper in the near future.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
arch/riscv/mm/fault.c | 52 ++++++++++++++++++++++++++++++++-------------------
1 file changed, 33 insertions(+), 19 deletions(-)
diff --git a/arch/riscv/mm/fault.c b/arch/riscv/mm/fault.c
index 04ed6f8acae4f..b2bcaf10d13f1 100644
--- a/arch/riscv/mm/fault.c
+++ b/arch/riscv/mm/fault.c
@@ -167,14 +167,16 @@ bad_area(struct pt_regs *regs, struct mm_struct *mm, int code,
static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long addr)
{
- pgd_t *pgd, *pgd_k;
- pud_t *pud_k;
- p4d_t *p4d_k;
- pmd_t *pmd_k;
- pte_t *pte_k;
+ pgd_t *pgdp_k, *pgdp, pgd_k;
+ p4d_t *p4dp_k, *p4dp;
+ pud_t *pudp_k, *pudp, pud_k;
+ pmd_t *pmdp_k, *pmdp, pmd_k;
+ pte_t *ptep_k;
int index;
unsigned long pfn;
+ BUILD_BUG_ON(CONFIG_PGTABLE_LEVELS != 5 && CONFIG_PGTABLE_LEVELS != 2);
+
/* User mode accesses just cause a SIGSEGV */
if (user_mode(regs))
return do_trap(regs, SIGSEGV, code, addr);
@@ -189,39 +191,51 @@ static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long a
*/
index = pgd_index(addr);
pfn = csr_read(CSR_SATP) & SATP_PPN;
- pgd = (pgd_t *)pfn_to_virt(pfn) + index;
- pgd_k = init_mm.pgd + index;
- if (!pgd_present(pgdp_get(pgd_k))) {
+ pgdp = (pgd_t *)pfn_to_virt(pfn) + index;
+ pgdp_k = init_mm.pgd + index;
+
+ pgd_k = pgdp_get(pgdp_k);
+ if (!pgd_present(pgd_k)) {
no_context(regs, addr);
return;
}
- set_pgd(pgd, pgdp_get(pgd_k));
+ if (CONFIG_PGTABLE_LEVELS == 5)
+ set_pgd(pgdp, pgd_k);
- p4d_k = p4d_offset(pgd_k, addr);
- if (!p4d_present(p4dp_get(p4d_k))) {
+ p4dp = p4d_offset(pgdp, addr);
+ p4dp_k = p4d_offset(pgdp_k, addr);
+ if (!p4d_present(p4dp_get(p4dp_k))) {
no_context(regs, addr);
return;
}
- pud_k = pud_offset(p4d_k, addr);
- if (!pud_present(pudp_get(pud_k))) {
+ pudp = pud_offset(p4dp, addr);
+ pudp_k = pud_offset(p4dp_k, addr);
+
+ pud_k = pudp_get(pudp_k);
+ if (!pud_present(pud_k)) {
no_context(regs, addr);
return;
}
- if (pud_leaf(pudp_get(pud_k)))
+ if (pud_leaf(pud_k))
goto flush_tlb;
/*
* Since the vmalloc area is global, it is unnecessary
* to copy individual PTEs
*/
- pmd_k = pmd_offset(pud_k, addr);
- if (!pmd_present(pmdp_get(pmd_k))) {
+ pmdp = pmd_offset(pudp, addr);
+ pmdp_k = pmd_offset(pudp_k, addr);
+
+ pmd_k = pmdp_get(pmdp_k);
+ if (!pmd_present(pmd_k)) {
no_context(regs, addr);
return;
}
- if (pmd_leaf(pmdp_get(pmd_k)))
+ if (CONFIG_PGTABLE_LEVELS == 2)
+ set_pmd(pmdp, pmd_k);
+ if (pmd_leaf(pmd_k))
goto flush_tlb;
/*
@@ -230,8 +244,8 @@ static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long a
* addresses. If we don't do this, this will just
* silently loop forever.
*/
- pte_k = pte_offset_kernel(pmd_k, addr);
- if (!pte_present(ptep_get(pte_k))) {
+ ptep_k = pte_offset_kernel(pmdp_k, addr);
+ if (!pte_present(ptep_get(ptep_k))) {
no_context(regs, addr);
return;
}
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 12/21] mm/pgtable: redefine PGTABLE_LEVEL enum with ascend order from PGD
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (10 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 11/21] riscv: mm: use proper set_pXd() for generic compile-time folded patable in vmalloc_fault() Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 13/21] x86/mm: Introduce helper for checking direct map 1G page support Yeoreum Yun
` (9 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc, Yeoreum Yun
The PGTABLE_LEVEL enum values appear to be ordered in the opposite direction
from their intended usage.
Intuitively, higher page table levels should have smaller enum values,
but PTE is currently assigned 0.
For consistency and cleanup, reverse the enum value ordering.
Since there is no current user relies on these numbers to be ascending from
PTE->PGD, so it can be changed to be ascending from PGD->PTE, in the
direction of the page table walk.
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
include/linux/pgtable.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index e3c8ab96941c5..3186096a6e130 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -2288,11 +2288,11 @@ static inline bool arch_has_pfn_modify_check(void)
typedef unsigned int pgtbl_mod_mask;
enum pgtable_level {
- PGTABLE_LEVEL_PTE = 0,
- PGTABLE_LEVEL_PMD,
- PGTABLE_LEVEL_PUD,
+ PGTABLE_LEVEL_PGD = 0,
PGTABLE_LEVEL_P4D,
- PGTABLE_LEVEL_PGD,
+ PGTABLE_LEVEL_PUD,
+ PGTABLE_LEVEL_PMD,
+ PGTABLE_LEVEL_PTE,
};
static inline const char *pgtable_level_to_str(enum pgtable_level level)
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 13/21] x86/mm: Introduce helper for checking direct map 1G page support
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (11 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 12/21] mm/pgtable: redefine PGTABLE_LEVEL enum with ascend order from PGD Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 14/21] x86: mm: use pgtable_level enum in effective_prot_pXd() Yeoreum Yun
` (8 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc, Yeoreum Yun, Sohil Mehta
From: Dave Hansen <dave.hansen@linux.intel.com>
There is an existing variable (direct_gbpages) that says whether the
kernel can and should use 1G pages in the direct map. It is driven
by a bunch of other machinery. At least:
1. Hardware support for 1G pages
2. Kconfig support for 1G direct mappings
3. Kernel command line overrides
Most code just checks the 'direct_gbpages' variable itself. But there
are cases where 1G mappings are compile-time disabled (via
X86_DIRECT_GBPAGES) and 'direct_gbpages' is always 0. Unfortunately,
that constraint is invisible to the compiler.
This opacity has been historically functionally harmless; it only
leaves a bit of dead code. But, there are plans to tigthen up the
compile-time checks around folded page table levels. The build will
break if that dead code appears reachable to the compiler. Making
the compile-time config visible to the compiler fixes the build.
Add a helper to replace 'direct_gbpages' checks. Check the Kconfig
option and base CPU support before looking at the variable.
This lets the compiler optimize things better, especially
collapse_pud_page() where most of the function can now be optimized
out when the PUD level is folded.
Notes:
Use boot_cpu_has() instead of cpu_feature_enabled(). There's no
required/disabled features for 1G pages themselves
(X86_DIRECT_GBPAGES is for kernel mappings only) and the
static_cpu_has() infrastructure is just gets in the compiler's way.
This makes 64-bit build marginally larger (20 bytes in one compile)
and 32-bit builds less marginally _smaller_ (~700 bytes).
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Tested-by: Yeoreum Yun <yeoreum.yun@arm.com>
Link: https://lore.kernel.org/all/20260902-dummy_ptxp3-v3-15-5d8f5b17c25c@arm.com/ [1]
Reviewed-by: Sohil Mehta <sohil.mehta@intel.com>
---
arch/x86/include/asm/pgtable.h | 14 ++++++++++++++
arch/x86/kernel/cpu/common.c | 2 +-
arch/x86/kernel/machine_kexec_64.c | 2 +-
arch/x86/mm/init.c | 2 +-
arch/x86/mm/pat/set_memory.c | 6 +++---
5 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index d5f4917c1edcb..c7adc00d49863 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -1163,6 +1163,20 @@ static inline int pgd_none(pgd_t pgd)
#ifndef __ASSEMBLER__
extern int direct_gbpages;
+static inline bool direct_gbpages_enabled(void)
+{
+ /* Check the direct map config option: */
+ if (!IS_ENABLED(CONFIG_X86_DIRECT_GBPAGES))
+ return false;
+
+ /* Check the CPU feature: */
+ if (!boot_cpu_has(X86_FEATURE_GBPAGES))
+ return false;
+
+ /* Check the command-line and early setup variable: */
+ return direct_gbpages;
+}
+
void init_mem_mapping(void);
void early_alloc_pgt_buf(void);
void __init poking_init(void);
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index c7352827f491d..4693ba98ca380 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -2660,7 +2660,7 @@ void __init arch_cpu_finalize_init(void)
* Right now we don't do that with gbpages because there seems
* very little benefit for that case.
*/
- if (!direct_gbpages)
+ if (!direct_gbpages_enabled())
set_memory_4k((unsigned long)__va(0), 1);
} else {
fpu__init_check_bugs();
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c
index c3f4a389992da..0da0e89f2611a 100644
--- a/arch/x86/kernel/machine_kexec_64.c
+++ b/arch/x86/kernel/machine_kexec_64.c
@@ -257,7 +257,7 @@ static int init_pgtable(struct kimage *image, unsigned long control_page)
info.kernpg_flag |= _PAGE_ENC;
}
- if (direct_gbpages)
+ if (direct_gbpages_enabled())
info.direct_gbpages = true;
for (i = 0; i < nr_pfn_mapped; i++) {
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 079f8c7e9e3cd..f0f4a06584c61 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -251,7 +251,7 @@ static void __init probe_page_size_mask(void)
__default_kernel_pte_mask &= ~_PAGE_GLOBAL;
/* Enable 1 GB linear kernel mappings if available: */
- if (direct_gbpages && boot_cpu_has(X86_FEATURE_GBPAGES)) {
+ if (direct_gbpages_enabled()) {
printk(KERN_INFO "Using GB pages for direct mapping\n");
page_size_mask |= 1 << PG_LEVEL_1G;
} else {
diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
index a1a061d995b31..261dda5f9f57c 100644
--- a/arch/x86/mm/pat/set_memory.c
+++ b/arch/x86/mm/pat/set_memory.c
@@ -128,7 +128,7 @@ void arch_report_meminfo(struct seq_file *m)
seq_printf(m, "DirectMap4M: %8lu kB\n",
direct_pages_count[PG_LEVEL_2M] << 12);
#endif
- if (direct_gbpages)
+ if (direct_gbpages_enabled())
seq_printf(m, "DirectMap1G: %8lu kB\n",
direct_pages_count[PG_LEVEL_1G] << 20);
}
@@ -1315,7 +1315,7 @@ static int collapse_pud_page(pud_t *pud, unsigned long addr,
pmd_t *pmd, first;
int i;
- if (!direct_gbpages)
+ if (!direct_gbpages_enabled())
return 0;
addr &= PUD_MASK;
@@ -1697,7 +1697,7 @@ static int populate_pud(struct cpa_data *cpa, unsigned long start, p4d_t *p4d,
/*
* Map everything starting from the Gb boundary, possibly with 1G pages
*/
- while (boot_cpu_has(X86_FEATURE_GBPAGES) && end - start >= PUD_SIZE) {
+ while (direct_gbpages_enabled() && end - start >= PUD_SIZE) {
set_pud(pud, pud_mkhuge(pfn_pud(cpa->pfn,
canon_pgprot(pud_pgprot))));
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 14/21] x86: mm: use pgtable_level enum in effective_prot_pXd()
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (12 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 13/21] x86/mm: Introduce helper for checking direct map 1G page support Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 15/21] x86: mm: carve out the generic compile-time folded pgtable case in effective_prot() Yeoreum Yun
` (7 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc, Yeoreum Yun
Instead of using hard-coded integers in effective_prot_pXd(), use the
page-table level enum so that architecture code does not need to know
the numeric value of each page-table level, while also providing type
safety.
This also prepares for using generic MM helpers, mm_first_pgtable_level()
which use symbolic names for page-table levels rather than integers.
There should be no functional change.
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
arch/x86/mm/dump_pagetables.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c
index 2afa7a23340e9..a18a61e732c3d 100644
--- a/arch/x86/mm/dump_pagetables.c
+++ b/arch/x86/mm/dump_pagetables.c
@@ -248,13 +248,13 @@ static void note_wx(struct pg_state *st, unsigned long addr)
(void *)st->start_address);
}
-static void effective_prot(struct ptdump_state *pt_st, int level, u64 val)
+static void effective_prot(struct ptdump_state *pt_st, enum pgtable_level level, u64 val)
{
struct pg_state *st = container_of(pt_st, struct pg_state, ptdump);
pgprotval_t prot = val & PTE_FLAGS_MASK;
pgprotval_t effective;
- if (level > 0) {
+ if (level > PGTABLE_LEVEL_PGD) {
pgprotval_t higher_prot = st->prot_levels[level - 1];
effective = (higher_prot & prot & (_PAGE_USER | _PAGE_RW)) |
@@ -268,27 +268,27 @@ static void effective_prot(struct ptdump_state *pt_st, int level, u64 val)
static void effective_prot_pte(struct ptdump_state *st, pte_t pte)
{
- effective_prot(st, 4, pte_val(pte));
+ effective_prot(st, PGTABLE_LEVEL_PTE, pte_val(pte));
}
static void effective_prot_pmd(struct ptdump_state *st, pmd_t pmd)
{
- effective_prot(st, 3, pmd_val(pmd));
+ effective_prot(st, PGTABLE_LEVEL_PMD, pmd_val(pmd));
}
static void effective_prot_pud(struct ptdump_state *st, pud_t pud)
{
- effective_prot(st, 2, pud_val(pud));
+ effective_prot(st, PGTABLE_LEVEL_PUD, pud_val(pud));
}
static void effective_prot_p4d(struct ptdump_state *st, p4d_t p4d)
{
- effective_prot(st, 1, p4d_val(p4d));
+ effective_prot(st, PGTABLE_LEVEL_P4D, p4d_val(p4d));
}
static void effective_prot_pgd(struct ptdump_state *st, pgd_t pgd)
{
- effective_prot(st, 0, pgd_val(pgd));
+ effective_prot(st, PGTABLE_LEVEL_PGD, pgd_val(pgd));
}
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 15/21] x86: mm: carve out the generic compile-time folded pgtable case in effective_prot()
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (13 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 14/21] x86: mm: use pgtable_level enum in effective_prot_pXd() Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 16/21] openrisc/pgtable: drop __pmd_offset() Yeoreum Yun
` (6 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc, Yeoreum Yun
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 the value for folded entries
really should be ignored.
For this, introduce mm_first_pgtable_level() to identify the first real
page-table level, move mm_pXd_folded() in !__ASSEMBLER__ 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.
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
arch/x86/mm/dump_pagetables.c | 6 +++--
include/linux/pgtable.h | 61 ++++++++++++++++++++++++++++++++-----------
2 files changed, 50 insertions(+), 17 deletions(-)
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c
index a18a61e732c3d..2acbe41eb58f2 100644
--- a/arch/x86/mm/dump_pagetables.c
+++ b/arch/x86/mm/dump_pagetables.c
@@ -38,6 +38,7 @@ struct pg_state {
bool check_wx;
unsigned long wx_pages;
struct seq_file *seq;
+ struct mm_struct *mm;
};
struct addr_marker {
@@ -254,7 +255,7 @@ static void effective_prot(struct ptdump_state *pt_st, enum pgtable_level level,
pgprotval_t prot = val & PTE_FLAGS_MASK;
pgprotval_t effective;
- if (level > PGTABLE_LEVEL_PGD) {
+ if (level > mm_first_pgtable_level(st->mm)) {
pgprotval_t higher_prot = st->prot_levels[level - 1];
effective = (higher_prot & prot & (_PAGE_USER | _PAGE_RW)) |
@@ -452,7 +453,8 @@ bool ptdump_walk_pgd_level_core(struct seq_file *m,
.level = -1,
.to_dmesg = dmesg,
.check_wx = checkwx,
- .seq = m
+ .seq = m,
+ .mm = mm,
};
ptdump_walk_pgd(&st.ptdump, mm, pgd);
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 3186096a6e130..ed7101a13ce9c 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -392,6 +392,22 @@ static inline void lazy_mmu_mode_pause(void) {}
static inline void lazy_mmu_mode_resume(void) {}
#endif
+/*
+ * On some architectures it depends on the mm if the p4d/pud or pmd
+ * layer of the page table hierarchy is folded or not.
+ */
+#ifndef mm_p4d_folded
+#define mm_p4d_folded(mm) __is_defined(__PAGETABLE_P4D_FOLDED)
+#endif
+
+#ifndef mm_pud_folded
+#define mm_pud_folded(mm) __is_defined(__PAGETABLE_PUD_FOLDED)
+#endif
+
+#ifndef mm_pmd_folded
+#define mm_pmd_folded(mm) __is_defined(__PAGETABLE_PMD_FOLDED)
+#endif
+
#ifndef pte_batch_hint
/**
* pte_batch_hint - Number of pages that can be added to batch without scanning.
@@ -2313,6 +2329,36 @@ static inline const char *pgtable_level_to_str(enum pgtable_level level)
}
}
+#ifdef CONFIG_MMU
+/**
+ * mm_first_pgtable_level - return the first non-folded page-table level
+ * @mm: The mm structure.
+ *
+ * With runtime- or compile-time folded page tables, page-table walkers
+ * effectively skip the folded top-level page tables, treating them as
+ * always-present entries pointing to the next lower-level page table.
+ *
+ * Return the first page-table level in @mm that is not folded.
+ *
+ * Return: the first non-folded page-table level.
+ */
+static inline enum pgtable_level mm_first_pgtable_level(struct mm_struct *mm)
+{
+ /*
+ * "PMD folded" actually means "PMD is folded into PUD", and
+ * pud_present() etc. are hard-coded to look like present page table
+ * levels, whereby pmd_present() etc. contain real logic.
+ */
+ if (mm_pmd_folded(mm))
+ return PGTABLE_LEVEL_PMD;
+ if (mm_pud_folded(mm))
+ return PGTABLE_LEVEL_PUD;
+ if (mm_p4d_folded(mm))
+ return PGTABLE_LEVEL_P4D;
+ return PGTABLE_LEVEL_PGD;
+}
+#endif /* CONFIG_MMU */
+
void ptval_bytes_to_hex_str(char *buf, size_t buf_size, const void *entry, size_t entry_size);
#define ptval_to_str(buf, val) \
@@ -2349,21 +2395,6 @@ void ptval_bytes_to_hex_str(char *buf, size_t buf_size, const void *entry, size_
#ifndef has_transparent_pud_hugepage
#define has_transparent_pud_hugepage() IS_BUILTIN(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)
#endif
-/*
- * On some architectures it depends on the mm if the p4d/pud or pmd
- * layer of the page table hierarchy is folded or not.
- */
-#ifndef mm_p4d_folded
-#define mm_p4d_folded(mm) __is_defined(__PAGETABLE_P4D_FOLDED)
-#endif
-
-#ifndef mm_pud_folded
-#define mm_pud_folded(mm) __is_defined(__PAGETABLE_PUD_FOLDED)
-#endif
-
-#ifndef mm_pmd_folded
-#define mm_pmd_folded(mm) __is_defined(__PAGETABLE_PMD_FOLDED)
-#endif
#ifndef p4d_offset_lockless
#define p4d_offset_lockless(pgdp, pgd, address) p4d_offset(&(pgd), address)
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 16/21] openrisc/pgtable: drop __pmd_offset()
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (14 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 15/21] x86: mm: carve out the generic compile-time folded pgtable case in effective_prot() Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 17/21] mm/pgtable: optimize pmdp_get() and friends for folded pagetable levels Yeoreum Yun
` (5 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc
From: "David Hildenbrand (Arm)" <david@kernel.org>
The macro is unused, and will collide with a folded page table helper.
Let's just remove it.
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
arch/openrisc/include/asm/pgtable.h | 3 ---
1 file changed, 3 deletions(-)
diff --git a/arch/openrisc/include/asm/pgtable.h b/arch/openrisc/include/asm/pgtable.h
index 13afcc0bd8631..7fceed641610c 100644
--- a/arch/openrisc/include/asm/pgtable.h
+++ b/arch/openrisc/include/asm/pgtable.h
@@ -331,9 +331,6 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
return ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK));
}
-#define __pmd_offset(address) \
- (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
-
#define PFN_PTE_SHIFT PAGE_SHIFT
#define pte_pfn(x) ((unsigned long)(((x).pte)) >> PAGE_SHIFT)
#define pfn_pte(pfn, prot) __pte((((pfn) << PAGE_SHIFT)) | pgprot_val(prot))
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 17/21] mm/pgtable: optimize pmdp_get() and friends for folded pagetable levels
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (15 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 16/21] openrisc/pgtable: drop __pmd_offset() Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 18/21] mm/pgtable: catch abuse of folded dummy pgd_t/p4d_t/pud_t Yeoreum Yun
` (4 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc
From: "David Hildenbrand (Arm)" <david@kernel.org>
Using pmdp_get() and friends in common code on a kernel config with
folded page tables is suboptimal: they default to a READ_ONCE(), forcing
the compiler to actually read that value even though it will not actually
be used afterwards.
This was recently reported by Christophe Leroy [1] and block conversion
of more common code to pmdp_get() and friends.
(using pgdp_get() as one example)
Most of the code ignores the result from pgdp_get() on configs with
folded page tables entirely, as it's hardcoded:
pgd_present()==1 && pgd_leaf()==false
Common code will just treat it as a "this is a page table" and call
p4d_offset() or p4d_offset_lockless() for the next lower level, where
the obtained pgdp_get() result is ignored entirely.
So, return a dummy value and avoid any memory reads.
There is a catch, though:
1) If code calls pgd_val() and somehow relies on the data, it would now
see dummy values. The code really must be aware of folded page table
levels. Fortunately, code usually ignores pgd_val() completely for
page tables (with ptdump being one exception when calculating
effective permissions). it's checked + fixed the x86 ptdump mechanism.
2) If code passes the pgd_t to a function that would work on the result,
it would now see dummy values. The only concern is really passing
the pgd_t on the stack as a pointer to p4d_offset(). Most code that
would do that, should actually use p4d_offset_lockless(), which
handles this properly. it's checked + fixed problematic instances.
3) Calling set_pgd() / pgd_page() / pgd_page_vaddr() with a pgd_t obtained through
pgdp_get(). There was once such case in riscv code with set_pgd(), which
is fixed.
As an example, this is the generated code for perf_get_page_size() with
PGTABLE_LEVELS=3 on arm64:
Before:
00000000000052a0 <perf_get_page_size>:
...
52dc: d53b4234 mrs x20, DAIF
52e0: d50343df msr DAIFSet, #0x3
...
52fc: d35e9a69 ubfx x9, x19, #30, #9 /* pud_offset_lockless() */
5300: f9403508 ldr x8, [x8, #0x68]
5304: f869790a ldr x10, [x8, x9, lsl #3] /* pudp_get() */
5308: f90007ea str x10, [sp, #0x8]
530c: f8697908 ldr x8, [x8, x9, lsl #3] /* pudp_get() */
...
5360: 90000009 adrp x9, 0x5000 <perf_prepare_sample+0x548>
5364: 92746908 and x8, x8, #0x7ffffff000
5368: d3557675 ubfx x21, x19, #21, #9 /* pmd_offset_lockless() */
...
5394: f8757ac8 ldr x8, [x22, x21, lsl #3] /* pmdp_get() */
After:
0000000000052a0 <perf_get_page_size>:
...
52dc: d53b4234 mrs x20, DAIF
52e0: d50343df msr DAIFSet, #0x3
... /* no pud_offset_lockless() and pudp_get() */
5318: 90000009 adrp x9, 0x5000 <perf_prepare_sample+0x548>
531c: 92746908 and x8, x8, #0x7ffffff000
5320: d3557675 ubfx x21, x19, #21, #9 /* pmd_offset_lockless() */
...
5334: f8757ac8 ldr x8, [x22, x21, lsl #3] /* pmdp_get() */
[1] https://lore.kernel.org/all/0019d675-ce3d-4a5c-89ed-f126c45145c9@kernel.org/
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
include/asm-generic/pgtable-nop4d.h | 8 ++++++++
include/asm-generic/pgtable-nopmd.h | 8 ++++++++
include/asm-generic/pgtable-nopud.h | 8 ++++++++
3 files changed, 24 insertions(+)
diff --git a/include/asm-generic/pgtable-nop4d.h b/include/asm-generic/pgtable-nop4d.h
index 019c3f074b771..acd62ee233536 100644
--- a/include/asm-generic/pgtable-nop4d.h
+++ b/include/asm-generic/pgtable-nop4d.h
@@ -34,6 +34,14 @@ static inline bool pgd_leaf(pgd_t pgd) { return false; }
*/
#define set_pgd(pgdptr, pgdval) set_p4d((p4d_t *)(pgdptr), (p4d_t) { pgdval })
+static inline pgd_t pgdp_get(pgd_t *pgdp)
+{
+ pgd_t dummy = { 0 };
+
+ return dummy;
+}
+#define pgdp_get pgdp_get
+
static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address)
{
return (p4d_t *)pgd;
diff --git a/include/asm-generic/pgtable-nopmd.h b/include/asm-generic/pgtable-nopmd.h
index 1dd5b165234be..9322f07ddf1ef 100644
--- a/include/asm-generic/pgtable-nopmd.h
+++ b/include/asm-generic/pgtable-nopmd.h
@@ -43,6 +43,14 @@ static inline void pud_clear(pud_t *pud) { }
*/
#define set_pud(pudptr, pudval) set_pmd((pmd_t *)(pudptr), (pmd_t) { pudval })
+static inline pud_t pudp_get(pud_t *pudp)
+{
+ pud_t dummy = { 0 };
+
+ return dummy;
+}
+#define pudp_get pudp_get
+
static inline pmd_t * pmd_offset(pud_t * pud, unsigned long address)
{
return (pmd_t *)pud;
diff --git a/include/asm-generic/pgtable-nopud.h b/include/asm-generic/pgtable-nopud.h
index 5a2b0a81ae197..8f01abbb00503 100644
--- a/include/asm-generic/pgtable-nopud.h
+++ b/include/asm-generic/pgtable-nopud.h
@@ -41,6 +41,14 @@ static inline bool p4d_leaf(p4d_t p4d) { return false; }
*/
#define set_p4d(p4dptr, p4dval) set_pud((pud_t *)(p4dptr), (pud_t) { p4dval })
+static inline p4d_t p4dp_get(p4d_t *p4dp)
+{
+ p4d_t dummy = { 0 };
+
+ return dummy;
+}
+#define p4dp_get p4dp_get
+
static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
{
return (pud_t *)p4d;
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 18/21] mm/pgtable: catch abuse of folded dummy pgd_t/p4d_t/pud_t
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (16 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 17/21] mm/pgtable: optimize pmdp_get() and friends for folded pagetable levels Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 19/21] mm/pgtable: disallow calling (pgd|p4d|pud)_page, pgd_page_vaddr() and (p4d|pud)_pgtable with dummy Yeoreum Yun
` (3 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc
From: "David Hildenbrand (Arm)" <david@kernel.org>
Catch and prevent all abuse with dummy values on the stack
similar to:
pud_t pud = pudp_get(pudp);
pmd_t *pmdp = pud_offset(*pud, addr);
While this approach relies on the compiler propagating constants, it
should catch most of the issues in practice. It would have caught all
the issues were found through manual inspection.
To avoid build issues particularly on x86, where pgd_val() might not be
around in some inclusion paths, perform the new checks from wrapper
macros.
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
include/asm-generic/pgtable-nop4d.h | 23 ++++++++++++++++++-----
include/asm-generic/pgtable-nopmd.h | 24 ++++++++++++++++++------
include/asm-generic/pgtable-nopud.h | 24 ++++++++++++++++++------
3 files changed, 54 insertions(+), 17 deletions(-)
diff --git a/include/asm-generic/pgtable-nop4d.h b/include/asm-generic/pgtable-nop4d.h
index acd62ee233536..2d86325235da5 100644
--- a/include/asm-generic/pgtable-nop4d.h
+++ b/include/asm-generic/pgtable-nop4d.h
@@ -34,7 +34,7 @@ static inline bool pgd_leaf(pgd_t pgd) { return false; }
*/
#define set_pgd(pgdptr, pgdval) set_p4d((p4d_t *)(pgdptr), (p4d_t) { pgdval })
-static inline pgd_t pgdp_get(pgd_t *pgdp)
+static __always_inline pgd_t pgdp_get(pgd_t *pgdp)
{
pgd_t dummy = { 0 };
@@ -42,17 +42,30 @@ static inline pgd_t pgdp_get(pgd_t *pgdp)
}
#define pgdp_get pgdp_get
-static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address)
+#define pgd_check_dummy(pgd) BUILD_BUG_ON(__builtin_constant_p(pgd_val(pgd)))
+
+static __always_inline p4d_t *__p4d_offset(pgd_t *pgdp, unsigned long address)
{
- return (p4d_t *)pgd;
+ return (p4d_t *)pgdp;
}
-static inline p4d_t *p4d_offset_lockless(pgd_t *pgdp, pgd_t pgd,
+#define p4d_offset(pgdp, address) \
+({ \
+ pgd_check_dummy(*(pgdp)); \
+ __p4d_offset(pgdp, address); \
+})
+
+static __always_inline p4d_t *__p4d_offset_lockless(pgd_t *pgdp, pgd_t pgd,
unsigned long address)
{
return (p4d_t *)pgdp;
}
-#define p4d_offset_lockless p4d_offset_lockless
+
+#define p4d_offset_lockless(pgdp, pgd, address) \
+({ \
+ pgd_check_dummy(*(pgdp)); \
+ __p4d_offset_lockless(pgdp, pgd, address); \
+})
#define p4d_val(x) (pgd_val((x).pgd))
#define __p4d(x) ((p4d_t) { __pgd(x) })
diff --git a/include/asm-generic/pgtable-nopmd.h b/include/asm-generic/pgtable-nopmd.h
index 9322f07ddf1ef..bd40d3a5743ff 100644
--- a/include/asm-generic/pgtable-nopmd.h
+++ b/include/asm-generic/pgtable-nopmd.h
@@ -43,7 +43,7 @@ static inline void pud_clear(pud_t *pud) { }
*/
#define set_pud(pudptr, pudval) set_pmd((pmd_t *)(pudptr), (pmd_t) { pudval })
-static inline pud_t pudp_get(pud_t *pudp)
+static __always_inline pud_t pudp_get(pud_t *pudp)
{
pud_t dummy = { 0 };
@@ -51,18 +51,30 @@ static inline pud_t pudp_get(pud_t *pudp)
}
#define pudp_get pudp_get
-static inline pmd_t * pmd_offset(pud_t * pud, unsigned long address)
+#define pud_check_dummy(pud) BUILD_BUG_ON(__builtin_constant_p(pud_val(pud)))
+
+static __always_inline pmd_t *__pmd_offset(pud_t *pudp, unsigned long address)
{
- return (pmd_t *)pud;
+ return (pmd_t *)pudp;
}
-#define pmd_offset pmd_offset
-static inline pmd_t *pmd_offset_lockless(pud_t *pudp, pud_t pud,
+#define pmd_offset(pudp, address) \
+({ \
+ pud_check_dummy(*(pudp)); \
+ __pmd_offset(pudp, address); \
+})
+
+static __always_inline pmd_t *__pmd_offset_lockless(pud_t *pudp, pud_t pud,
unsigned long address)
{
return (pmd_t *)pudp;
}
-#define pmd_offset_lockless pmd_offset_lockless
+
+#define pmd_offset_lockless(pudp, pud, address) \
+({ \
+ pud_check_dummy(*(pudp)); \
+ __pmd_offset_lockless(pudp, pud, address); \
+})
#define pmd_val(x) (pud_val((x).pud))
#define __pmd(x) ((pmd_t) { __pud(x) } )
diff --git a/include/asm-generic/pgtable-nopud.h b/include/asm-generic/pgtable-nopud.h
index 8f01abbb00503..7475d0bd0f2e0 100644
--- a/include/asm-generic/pgtable-nopud.h
+++ b/include/asm-generic/pgtable-nopud.h
@@ -41,7 +41,7 @@ static inline bool p4d_leaf(p4d_t p4d) { return false; }
*/
#define set_p4d(p4dptr, p4dval) set_pud((pud_t *)(p4dptr), (pud_t) { p4dval })
-static inline p4d_t p4dp_get(p4d_t *p4dp)
+static __always_inline p4d_t p4dp_get(p4d_t *p4dp)
{
p4d_t dummy = { 0 };
@@ -49,18 +49,30 @@ static inline p4d_t p4dp_get(p4d_t *p4dp)
}
#define p4dp_get p4dp_get
-static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
+#define p4d_check_dummy(p4d) BUILD_BUG_ON(__builtin_constant_p(p4d_val(p4d)))
+
+static __always_inline pud_t *__pud_offset(p4d_t *p4dp, unsigned long address)
{
- return (pud_t *)p4d;
+ return (pud_t *)p4dp;
}
-#define pud_offset pud_offset
-static inline pud_t *pud_offset_lockless(p4d_t *p4dp, p4d_t p4d,
+#define pud_offset(p4dp, address) \
+({ \
+ p4d_check_dummy(*(p4dp)); \
+ __pud_offset(p4dp, address); \
+})
+
+static __always_inline pud_t *__pud_offset_lockless(p4d_t *p4dp, p4d_t p4d,
unsigned long address)
{
return (pud_t *)p4dp;
}
-#define pud_offset_lockless pud_offset_lockless
+
+#define pud_offset_lockless(p4dp, p4d, address) \
+({ \
+ p4d_check_dummy(*(p4dp)); \
+ __pud_offset_lockless(p4dp, p4d, address); \
+})
#define pud_val(x) (p4d_val((x).p4d))
#define __pud(x) ((pud_t) { __p4d(x) })
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 19/21] mm/pgtable: disallow calling (pgd|p4d|pud)_page, pgd_page_vaddr() and (p4d|pud)_pgtable with dummy
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (17 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 18/21] mm/pgtable: catch abuse of folded dummy pgd_t/p4d_t/pud_t Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 20/21] mm/pgtable: disallow calling folded set_pgd/set_p4d/set_pud " Yeoreum Yun
` (2 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc, Yeoreum Yun
From: "David Hildenbrand (Arm)" <david@kernel.org>
These helpers silently fallback to the folded helpers. With e.g., pdgp_get()
returning dummy values, pgd_page_vaddr(pgdp_get(pgdp)) will now behave
differently than pgd_page_vaddr(*pgdp).
Disallow calling (pgd|p4d|pud)_page() entirely, and catch when passing a
dummy value to pgd_page_vaddr() and (p4d|pud)_pgtable.
This will catch most abuse of dummy pXdp value at compile time --
so far there were none, and it better stay that way.
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Co-developed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
include/asm-generic/pgtable-nop4d.h | 8 ++++++--
include/asm-generic/pgtable-nopmd.h | 8 ++++++--
include/asm-generic/pgtable-nopud.h | 8 ++++++--
3 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/include/asm-generic/pgtable-nop4d.h b/include/asm-generic/pgtable-nop4d.h
index 2d86325235da5..d2dccf7542da5 100644
--- a/include/asm-generic/pgtable-nop4d.h
+++ b/include/asm-generic/pgtable-nop4d.h
@@ -70,8 +70,12 @@ static __always_inline p4d_t *__p4d_offset_lockless(pgd_t *pgdp, pgd_t pgd,
#define p4d_val(x) (pgd_val((x).pgd))
#define __p4d(x) ((p4d_t) { __pgd(x) })
-#define pgd_page(pgd) (p4d_page((p4d_t){ pgd }))
-#define pgd_page_vaddr(pgd) ((unsigned long)(p4d_pgtable((p4d_t){ pgd })))
+#define pgd_page(pgd) ({ BUILD_BUG(); (struct page *)NULL; })
+#define pgd_page_vaddr(pgd) \
+({ \
+ pgd_check_dummy(pgd); \
+ (unsigned long)p4d_pgtable((p4d_t) { pgd }); \
+})
/*
* allocating and freeing a p4d is trivial: the 1-entry p4d is
diff --git a/include/asm-generic/pgtable-nopmd.h b/include/asm-generic/pgtable-nopmd.h
index bd40d3a5743ff..2afbf2d8659dc 100644
--- a/include/asm-generic/pgtable-nopmd.h
+++ b/include/asm-generic/pgtable-nopmd.h
@@ -79,8 +79,12 @@ static __always_inline pmd_t *__pmd_offset_lockless(pud_t *pudp, pud_t pud,
#define pmd_val(x) (pud_val((x).pud))
#define __pmd(x) ((pmd_t) { __pud(x) } )
-#define pud_page(pud) (pmd_page((pmd_t){ pud }))
-#define pud_pgtable(pud) ((pmd_t *)(pmd_page_vaddr((pmd_t){ pud })))
+#define pud_page(pud) ({ BUILD_BUG(); (struct page *)NULL; })
+#define pud_pgtable(pud) \
+({ \
+ pud_check_dummy(pud); \
+ ((pmd_t *)(pmd_page_vaddr((pmd_t) { pud }))); \
+})
/*
* allocating and freeing a pmd is trivial: the 1-entry pmd is
diff --git a/include/asm-generic/pgtable-nopud.h b/include/asm-generic/pgtable-nopud.h
index 7475d0bd0f2e0..3264673c0c386 100644
--- a/include/asm-generic/pgtable-nopud.h
+++ b/include/asm-generic/pgtable-nopud.h
@@ -77,8 +77,12 @@ static __always_inline pud_t *__pud_offset_lockless(p4d_t *p4dp, p4d_t p4d,
#define pud_val(x) (p4d_val((x).p4d))
#define __pud(x) ((pud_t) { __p4d(x) })
-#define p4d_page(p4d) (pud_page((pud_t){ p4d }))
-#define p4d_pgtable(p4d) ((pud_t *)(pud_pgtable((pud_t){ p4d })))
+#define p4d_page(p4d) ({ BUILD_BUG(); (struct page *)NULL; })
+#define p4d_pgtable(p4d) \
+({ \
+ p4d_check_dummy(p4d); \
+ ((pud_t *)(pud_pgtable((pud_t) { p4d }))); \
+})
/*
* allocating and freeing a pud is trivial: the 1-entry pud is
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 20/21] mm/pgtable: disallow calling folded set_pgd/set_p4d/set_pud with dummy
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (18 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 19/21] mm/pgtable: disallow calling (pgd|p4d|pud)_page, pgd_page_vaddr() and (p4d|pud)_pgtable with dummy Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 10:55 ` [PATCH 21/21] Documentation: mm: clarify behaviour of compile-time folded page tables Yeoreum Yun
2026-09-21 21:11 ` [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Muhammad Usama Anjum
21 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc, Yeoreum Yun
From: "David Hildenbrand (Arm)" <david@kernel.org>
pXdp_get() could return a dummy value for a page-table level folded at
compile time. Passing this value to set_pXd() could cause unexpected
behavior.
Prevent this at compile time by ensuring that all calls to
set_pgd()/set_p4d()/set_pud() are compiled out for folded page-table
levels. Make the compiler complain if these helpers are called with
dummy values.
Since there are places where set_pXd() is called even when
the corresponding page-table level is folded at compile time,
drop the incorrect comments for set_pXd().
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Co-developed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
include/asm-generic/pgtable-nop4d.h | 11 ++++++-----
include/asm-generic/pgtable-nopmd.h | 10 +++++-----
include/asm-generic/pgtable-nopud.h | 12 +++++++-----
3 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/include/asm-generic/pgtable-nop4d.h b/include/asm-generic/pgtable-nop4d.h
index d2dccf7542da5..12b01768134b5 100644
--- a/include/asm-generic/pgtable-nop4d.h
+++ b/include/asm-generic/pgtable-nop4d.h
@@ -28,11 +28,12 @@ static inline bool pgd_leaf(pgd_t pgd) { return false; }
#define pgd_populate(mm, pgd, p4d) do { } while (0)
#define pgd_populate_safe(mm, pgd, p4d) do { } while (0)
-/*
- * (p4ds are folded into pgds so this doesn't get actually called,
- * but the define is needed for a generic inline function.)
- */
-#define set_pgd(pgdptr, pgdval) set_p4d((p4d_t *)(pgdptr), (p4d_t) { pgdval })
+
+#define set_pgd(pgdptr, pgdval) \
+({ \
+ pgd_check_dummy(pgdval); \
+ set_p4d((p4d_t *)(pgdptr), (p4d_t) { pgdval }); \
+})
static __always_inline pgd_t pgdp_get(pgd_t *pgdp)
{
diff --git a/include/asm-generic/pgtable-nopmd.h b/include/asm-generic/pgtable-nopmd.h
index 2afbf2d8659dc..11b04c1071295 100644
--- a/include/asm-generic/pgtable-nopmd.h
+++ b/include/asm-generic/pgtable-nopmd.h
@@ -37,11 +37,11 @@ static inline void pud_clear(pud_t *pud) { }
#define pud_populate(mm, pmd, pte) do { } while (0)
-/*
- * (pmds are folded into puds so this doesn't get actually called,
- * but the define is needed for a generic inline function.)
- */
-#define set_pud(pudptr, pudval) set_pmd((pmd_t *)(pudptr), (pmd_t) { pudval })
+#define set_pud(pudptr, pudval) \
+({ \
+ pud_check_dummy(pudval); \
+ set_pmd((pmd_t *)(pudptr), (pmd_t) { pudval }); \
+})
static __always_inline pud_t pudp_get(pud_t *pudp)
{
diff --git a/include/asm-generic/pgtable-nopud.h b/include/asm-generic/pgtable-nopud.h
index 3264673c0c386..5ee8f1852cd8c 100644
--- a/include/asm-generic/pgtable-nopud.h
+++ b/include/asm-generic/pgtable-nopud.h
@@ -35,11 +35,13 @@ static inline bool p4d_leaf(p4d_t p4d) { return false; }
#define p4d_populate(mm, p4d, pud) do { } while (0)
#define p4d_populate_safe(mm, p4d, pud) do { } while (0)
-/*
- * (puds are folded into p4ds so this doesn't get actually called,
- * but the define is needed for a generic inline function.)
- */
-#define set_p4d(p4dptr, p4dval) set_pud((pud_t *)(p4dptr), (pud_t) { p4dval })
+
+#define set_p4d(p4dptr, p4dval) \
+({ \
+ p4d_check_dummy(p4dval); \
+ set_pud((pud_t *)(p4dptr), (pud_t) { p4dval }); \
+})
+
static __always_inline p4d_t p4dp_get(p4d_t *p4dp)
{
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 21/21] Documentation: mm: clarify behaviour of compile-time folded page tables
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (19 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 20/21] mm/pgtable: disallow calling folded set_pgd/set_p4d/set_pud " Yeoreum Yun
@ 2026-09-21 10:55 ` Yeoreum Yun
2026-09-21 16:20 ` Randy Dunlap
2026-09-21 21:11 ` [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Muhammad Usama Anjum
21 siblings, 1 reply; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 10:55 UTC (permalink / raw)
To: Russell King, Huacai Chen, WANG Xuerui, Thomas Bogendoerfer,
Catalin Marinas, Will Deacon, Arnd Bergmann, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Johannes Weiner, David Hildenbrand,
Michal Hocko, Lorenzo Stoakes, Tianrui Zhao, Bibo Mao,
Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc
From: "David Hildenbrand (Arm)" <david@kernel.org>
Compile-time folded page tables are not necessarily easy to understand, and even
people the were once familiar with the concept might need to refresh their memory.
Add proper documentation, including a nice diagram, for the current design.
Mention details about dummy functions, including the recently changed pXdp_get()
helpers.
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
Documentation/mm/page_tables.rst | 84 +++++++++++++++++++++++++++++++++++-----
1 file changed, 75 insertions(+), 9 deletions(-)
diff --git a/Documentation/mm/page_tables.rst b/Documentation/mm/page_tables.rst
index 126c876282509..84f2715c7de0a 100644
--- a/Documentation/mm/page_tables.rst
+++ b/Documentation/mm/page_tables.rst
@@ -143,15 +143,81 @@ pointers on each level is architecture-defined.::
Page Table Folding
==================
-If the architecture does not use all the page table levels, they can be *folded*
-which means skipped, and all operations performed on page tables will be
-compile-time augmented to just skip a level when accessing the next lower
-level.
-
-Page table handling code that wishes to be architecture-neutral, such as the
-virtual memory manager, will need to be written so that it traverses all of the
-currently five levels. This style should also be preferred for
-architecture-specific code, so as to be robust to future changes.
+Not all architectures support 5-level page tables; while for some of them
+the exact number of supported page table levels is known at compile time,
+others can determine the number of page table levels at runtime based on
+hardware support and address space sizes.
+
+Generic page table walking code always assumes that 5 levels of page table
+exist. To make page table walking code not have to worry about that,
+`compile-time folding` and `runtime folding` of page tables are used.
+Compile-time folding is mostly handled in common code, whereas runtime folding
+is exclusively handled in architecture code.
+
+This description focuses on generic compile-time folded page tables; for
+architecture-specific variants, some details can vary, however, without
+affecting common page table walkers.
+
+When walking folded page tables, all upper page table levels up to the supported
+level are skipped in page table walkers: this is achieved by (a) treating
+entries in upper page table levels as present and pointing at a page table; and
+(b) having page table walkers cast the entry pointer to the next-level entry
+instead of dereferencing that table. From the perspective of a page table
+walker, the entry points at itself.
+
+Assuming compile-time folded 4-level page tables, to achieve (a), pgd_present()
+and pgd_leaf() are hard-coded to indicate a present page table entry that
+points at a page table, and to achieve (b) p4d_offset() and
+p4d_offset_lockless() simply cast the page table entry pointer to the next
+lower level.
+
+In the current design, this is further modeled by having the P4D have a
+single page table entry::
+
+ PGD
+ --> +------+ NOP4D
+ | ptr0 |-------> +------+ PUD
+ | ptr1 |- | ptr0 |-------> +-----+
+ | ptr2 | \ +------+ | ptr |-------> ...
+ | ptr3 | \ | ptr |
+ ... \ ..
+ \ NOP4D
+ +----> +------+ PUD
+ | ptr1 |-------> +-----+
+ +------+ | ptr |-------> ...
+ | ptr |
+ ...
+
+Note that the arrows from PGD to NOP4D represent page-table-walker
+transitions, not pointers stored in the pgd entries.
+
+Using p4d as an example, `nop4d`/`p4d folded` translates to the following:
+
+- p4d is considered folded into pgd; both are operating on the same page
+ table.
+
+- Most pgd_* helpers are hard-coded dummy functions that ignore the passed
+ pgd_t values entirely. Exceptions are pgd_val() and low-level helpers
+ set_pgd() + pgd_page_vaddr(), which effectively translate to set_p4d()/
+ p4d_pgtable() to keep existing arch code working.
+
+ Architectures must provide p4d_* helpers (unless further common
+ compile-time folding applies).
+
+- PTRS_PER_P4D is hard-coded to 1. Architectures must define PTRS_PER_PGD.
+
+To avoid reading a value that will never be used but cannot be entirely
+optimized out, compile-time folded page table code also makes pXdp_get()
+return a constant dummy value.
+
+In common code, this only affects pXd_val() when used for printing page
+table entries for debugging purposes. As we don't want architecture code
+that uses set_pXd(), pgd_page_vaddr() or pXd_pgtable() to accidentally
+operate on dummy values, the compiler will error out if it detects that the
+helpers are used with dummy values. For a folded level, pXd_page() must not
+be used and unconditionally triggers a compiler error. Architecture code must
+instead call the helpers on the proper first page table level: e.g., set_p4d()
+instead of set_pgd().
MMU, TLB, and Page Faults
--
2.43.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 21/21] Documentation: mm: clarify behaviour of compile-time folded page tables
2026-09-21 10:55 ` [PATCH 21/21] Documentation: mm: clarify behaviour of compile-time folded page tables Yeoreum Yun
@ 2026-09-21 16:20 ` Randy Dunlap
2026-09-21 20:26 ` Yeoreum Yun
0 siblings, 1 reply; 25+ messages in thread
From: Randy Dunlap @ 2026-09-21 16:20 UTC (permalink / raw)
To: Yeoreum Yun, Russell King, Huacai Chen, WANG Xuerui,
Thomas Bogendoerfer, Catalin Marinas, Will Deacon, Arnd Bergmann,
Andrew Morton, Kairui Song, Qi Zheng, Shakeel Butt, Barry Song,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Johannes Weiner,
David Hildenbrand, Michal Hocko, Lorenzo Stoakes, Tianrui Zhao,
Bibo Mao, Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-mips,
linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc
On 9/21/26 3:55 AM, Yeoreum Yun wrote:
> From: "David Hildenbrand (Arm)" <david@kernel.org>
>
> Compile-time folded page tables are not necessarily easy to understand, and even
> people the were once familiar with the concept might need to refresh their memory.
>
> Add proper documentation, including a nice diagram, for the current design.
> Mention details about dummy functions, including the recently changed pXdp_get()
> helpers.
>
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
Documentation/mm/page_tables.rst:197: WARNING: Bullet list ends without a blank line; unexpected unindent. [docutils]
See below for a fix.
> ---
> Documentation/mm/page_tables.rst | 84 +++++++++++++++++++++++++++++++++++-----
> 1 file changed, 75 insertions(+), 9 deletions(-)
>
> diff --git a/Documentation/mm/page_tables.rst b/Documentation/mm/page_tables.rst
> index 126c876282509..84f2715c7de0a 100644
> --- a/Documentation/mm/page_tables.rst
> +++ b/Documentation/mm/page_tables.rst
> @@ -143,15 +143,81 @@ pointers on each level is architecture-defined.::
> Page Table Folding
> ==================
>
> -If the architecture does not use all the page table levels, they can be *folded*
> -which means skipped, and all operations performed on page tables will be
> -compile-time augmented to just skip a level when accessing the next lower
> -level.
> -
> -Page table handling code that wishes to be architecture-neutral, such as the
> -virtual memory manager, will need to be written so that it traverses all of the
> -currently five levels. This style should also be preferred for
> -architecture-specific code, so as to be robust to future changes.
> +Not all architectures support 5-level page tables; while for some of them
> +the exact number of supported page table levels is known at compile time,
> +others can determine the number of page table levels at runtime based on
> +hardware support and address space sizes.
> +
> +Generic page table walking code always assumes that 5 levels of page table
> +exist. To make page table walking code not have to worry about that,
> +`compile-time folding` and `runtime folding` of page tables are used.
> +Compile-time folding is mostly handled in common code, whereas runtime folding
> +is exclusively handled in architecture code.
> +
> +This description focuses on generic compile-time folded page tables; for
> +architecture-specific variants, some details can vary, however, without
> +affecting common page table walkers.
> +
> +When walking folded page tables, all upper page table levels up to the supported
> +level are skipped in page table walkers: this is achieved by (a) treating
> +entries in upper page table levels as present and pointing at a page table; and
> +(b) having page table walkers cast the entry pointer to the next-level entry
> +instead of dereferencing that table. From the perspective of a page table
> +walker, the entry points at itself.
> +
> +Assuming compile-time folded 4-level page tables, to achieve (a), pgd_present()
> +and pgd_leaf() are hard-coded to indicate a present page table entry that
> +points at a page table, and to achieve (b) p4d_offset() and
> +p4d_offset_lockless() simply cast the page table entry pointer to the next
> +lower level.
> +
> +In the current design, this is further modeled by having the P4D have a
> +single page table entry::
> +
> + PGD
> + --> +------+ NOP4D
> + | ptr0 |-------> +------+ PUD
> + | ptr1 |- | ptr0 |-------> +-----+
> + | ptr2 | \ +------+ | ptr |-------> ...
> + | ptr3 | \ | ptr |
> + ... \ ..
> + \ NOP4D
> + +----> +------+ PUD
> + | ptr1 |-------> +-----+
> + +------+ | ptr |-------> ...
> + | ptr |
> + ...
> +
> +Note that the arrows from PGD to NOP4D represent page-table-walker
> +transitions, not pointers stored in the pgd entries.
> +
> +Using p4d as an example, `nop4d`/`p4d folded` translates to the following:
> +
> +- p4d is considered folded into pgd; both are operating on the same page
> + table.
table.
(add one more prefix space to align the indentation)
> +
> +- Most pgd_* helpers are hard-coded dummy functions that ignore the passed
> + pgd_t values entirely. Exceptions are pgd_val() and low-level helpers
> + set_pgd() + pgd_page_vaddr(), which effectively translate to set_p4d()/
> + p4d_pgtable() to keep existing arch code working.
> +
> + Architectures must provide p4d_* helpers (unless further common
> + compile-time folding applies).
> +
> +- PTRS_PER_P4D is hard-coded to 1. Architectures must define PTRS_PER_PGD.
> +
> +To avoid reading a value that will never be used but cannot be entirely
> +optimized out, compile-time folded page table code also makes pXdp_get()
> +return a constant dummy value.
> +
> +In common code, this only affects pXd_val() when used for printing page
> +table entries for debugging purposes. As we don't want architecture code
> +that uses set_pXd(), pgd_page_vaddr() or pXd_pgtable() to accidentally
> +operate on dummy values, the compiler will error out if it detects that the
> +helpers are used with dummy values. For a folded level, pXd_page() must not
> +be used and unconditionally triggers a compiler error. Architecture code must
> +instead call the helpers on the proper first page table level: e.g., set_p4d()
> +instead of set_pgd().
>
>
> MMU, TLB, and Page Faults
>
--
~Randy
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 21/21] Documentation: mm: clarify behaviour of compile-time folded page tables
2026-09-21 16:20 ` Randy Dunlap
@ 2026-09-21 20:26 ` Yeoreum Yun
0 siblings, 0 replies; 25+ messages in thread
From: Yeoreum Yun @ 2026-09-21 20:26 UTC (permalink / raw)
To: Randy Dunlap
Cc: Yeoreum Yun, Russell King, Huacai Chen, WANG Xuerui,
Thomas Bogendoerfer, Catalin Marinas, Will Deacon, Arnd Bergmann,
Andrew Morton, Kairui Song, Qi Zheng, Shakeel Butt, Barry Song,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Johannes Weiner,
David Hildenbrand, Michal Hocko, Lorenzo Stoakes, Tianrui Zhao,
Bibo Mao, Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Dave Hansen, Andy Lutomirski,
Peter Zijlstra, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
x86, H. Peter Anvin, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne, linux-arm-kernel,
linux-kernel, loongarch, linux-mips, linux-arch, linux-mm, kvm,
kvm-riscv, linux-riscv, linux-openrisc
Hi Randy,
>
>
> On 9/21/26 3:55 AM, Yeoreum Yun wrote:
> > From: "David Hildenbrand (Arm)" <david@kernel.org>
> >
> > Compile-time folded page tables are not necessarily easy to understand, and even
> > people the were once familiar with the concept might need to refresh their memory.
> >
> > Add proper documentation, including a nice diagram, for the current design.
> > Mention details about dummy functions, including the recently changed pXdp_get()
> > helpers.
> >
> > Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
>
> Documentation/mm/page_tables.rst:197: WARNING: Bullet list ends without a blank line; unexpected unindent. [docutils]
>
> See below for a fix.
[...]
> > +Note that the arrows from PGD to NOP4D represent page-table-walker
> > +transitions, not pointers stored in the pgd entries.
> > +
> > +Using p4d as an example, `nop4d`/`p4d folded` translates to the following:
> > +
> > +- p4d is considered folded into pgd; both are operating on the same page
> > + table.
>
> table.
> (add one more prefix space to align the indentation)
>
Thanks! I'll fix it!
[...]
--
Sincerely,
Yeoreum Yun
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (20 preceding siblings ...)
2026-09-21 10:55 ` [PATCH 21/21] Documentation: mm: clarify behaviour of compile-time folded page tables Yeoreum Yun
@ 2026-09-21 21:11 ` Muhammad Usama Anjum
21 siblings, 0 replies; 25+ messages in thread
From: Muhammad Usama Anjum @ 2026-09-21 21:11 UTC (permalink / raw)
To: Yeoreum Yun
Cc: usama.anjum, linux-arm-kernel, linux-kernel, loongarch,
linux-mips, linux-arch, linux-mm, kvm, kvm-riscv, linux-riscv,
linux-openrisc, Sohil Mehta, Russell King, Huacai Chen,
WANG Xuerui, Thomas Bogendoerfer, Catalin Marinas, Will Deacon,
Arnd Bergmann, Andrew Morton, Kairui Song, Qi Zheng,
Shakeel Butt, Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
Johannes Weiner, David Hildenbrand, Michal Hocko,
Lorenzo Stoakes, Tianrui Zhao, Bibo Mao, Anup Patel, Atish Patra,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Dave Hansen, Andy Lutomirski, Peter Zijlstra, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Jonas Bonn,
Stefan Kristiansson, Stafford Horne
On 21/09/2026 11:55 am, Yeoreum Yun wrote:
> Using ptep_get() and its counterparts in common code is suboptimal on
> kernel configurations with generic compile-time folded page tables.
> By default, ptep_get() and its friends expands to READ_ONCE(),
> forcing the compiler to emit a load even when the value is not used afterwards.
>
> This issue was recently reported by Christophe Leroy [1] for ppc32
> preventing futher code conversion to ptep_get()/pmdp_get()/... helper
> and the same behavior can also be observed on arm64 when built with
> 2- or 3-level page tables
>
> e.g) perf_get_page_size() in arm64 with CONFIG_PGTABLE_LEVEL=3:
>
> 00000000000052a0 <perf_get_page_size>:
> ...
> 52dc: d53b4234 mrs x20, DAIF
> 52e0: d50343df msr DAIFSet, #0x3
> ...
> 52fc: d35e9a69 ubfx x9, x19, #30, #9 /* pud_offset_lockless() */
> 5300: f9403508 ldr x8, [x8, #0x68]
> 5304: f869790a ldr x10, [x8, x9, lsl #3] /* pudp_get() */
> 5308: f90007ea str x10, [sp, #0x8]
> 530c: f8697908 ldr x8, [x8, x9, lsl #3] /* pudp_get() */
> ...
> 5360: 90000009 adrp x9, 0x5000 <perf_prepare_sample+0x548>
> 5364: 92746908 and x8, x8, #0x7ffffff000
> 5368: d3557675 ubfx x21, x19, #21, #9 /* pmd_offset_lockless() */
> ...
> 5394: f8757ac8 ldr x8, [x22, x21, lsl #3] /* pmdp_get() */
>
> Though PGTABLE_LEVEL=3, since the pudp_get() still remain with
> READ_ONCE(), there's redundant load for the pud which is folded.
>
> To prevent generating suboptimal code, make pXdp_get() return a dummy
> entry for compile-time folded page tables, make the helpers such as
> pXd_offset()/pXd_offset_lockless(), set_pXd() validate dummy entries
> at compile time to catch the wrong usage and prohibit calls to
> pXd_page() in pgtable-nopXd.h.
>
> This series does not change the behaviour of existing code that directly
> manipulates folded page-table levels using set_pgd(), pgd_page_vaddr(), and
> related helpers. Those helpers continue to behave as before.
>
> The new restrictions only apply to code that adopts the pXdp_get()-based
> access model for compile-time folded page tables.
>
> As the pXdp_get() can return *dummy* entry, some of code using
> the stack value where saves the pXdp_get() could be a problematic:
>
> 1. Passing address of stack value where saves the pXdp_get() result
> to pXd_offset() for example:
>
> pud_t *pudp, pud;
> pmd_t *pmdp;
>
> pud = pudp_get(pudp, address);
> pmdp = pmd_offset(&pud, pud, address);
>
> (e.g. host_pfn_mapping_level() in loongarch).
>
> 2. Using the pXdp_get() result to use as argument of pXd_val() and
> to check prot without checking pgtable is folded.
> for example, x86's effective_prot().
>
> 3. Using set_pXd() with pXdp_get() will set problematic dummy entry
> in folded page table like:
>
> set_pXd(pxdp, pXdp_get(pxdp_k));
>
> 4. Using pgd_page_vaddr() to get the first-level pgtable.
> passing dummy pxdp_get() for pgd_page_vaddr() will return wrong
> address. Therefore, make pgd_page_vaddr() and pXd_pgtable() to
> trigger the error for improper usage with folded dummy entry in the
> generic compile-time folded pgtable.
>
> Thanksfully, above cases are rare since (1) most of usage using
> pXd_offset() with result of upper pXd_offset(), (2) it's extreamely
> rare to use pXd_val() for non-leaf entry in the kernel,
> (3) is to handle the vmalloc_fault or set the first level of page table
> and (4) to setup early page table and etc.
>
> Therefore, properly handle this uncommon and problematic pattern, and
> document the current design of compile-time folded page tables.
>
> This patch is based on mm-unstable.
>
> Future work
> ===========
> - print_bad_page_map() and show_pte() still prints dummy values
> instead of printing the same content for all generic compile-time
> folded page tables. We might want to skip printing dummy values later.
>
> - We currently catch abuse of dummy values on the stack at compile-time by
> relying on constant propagation by the compiler. Usama's work [3] on using
> distinct types for sw vs. hw PTEs could help here as well."
>
> - Clean up vmalloc fault handling by synchronizing the vmalloc entry on
> 32-bit architectures. This code is almost identical across architectures.
>
> - Unfortunately, the current design of compile-time folded page tables appears
> to be internally consistent but confusing. For example,
> when CONFIG_PGTABLE_LEVELS is 2, p4d, pud, and pmd are expected to
> be folded into pgd. However, the architecture code uses set_pmd()
> to update the top-level page-table entry, even though it includes pgtable-nopmd.h.
>
> In the future, it would be good to eliminate this source of confusion,
> possibly by treating all folded upper levels consistently as dummy wrappers
> around the highest real page-table level:
>
> NOPGD
> --> +------+ P4D
> | ptr0 |-------> +------+ PUD
> +------+ | ptr0 |-------> +-----+
> | ptr1 |- | ptr | -------> ...
> | ptr2 | \ | ptr |
> | ptr3 | \ ...
> ... \
> \ PUD
> +----> +-----+
> | ptr | -------> ...
> | ptr |
> ...
>
> Link: [1] https://lore.kernel.org/all/0019d675-ce3d-4a5c-89ed-f126c45145c9@kernel.org/
> Link: [2] https://lore.kernel.org/all/20251113014656.2605447-1-samuel.holland@sifive.com/
> Link: [3] https://lore.kernel.org/r/74182e50-b54f-4d2d-a27f-3a59a538d6bc@arm.com
I applied all 21 patches to the declared base and built and booted the
kernels before and after on x86_64 and arm64 using virtme-ng.
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
>
> Patch History
> =============
> from RFC v3 to v1:
> - Drop and rebase for CONFIG_X86_DIRECT_GBPAGES and use the Dave's
> patch (https://lore.kernel.org/all/20260902194718.E1FF3041@davehans-spike.ostc.intel.com/)
> - Link to RFC v3: https://lore.kernel.org/r/20260902-dummy_ptxp3-v3-0-5d8f5b17c25c@arm.com
>
> from RFC v2 to RFC v3:
> - repasre commit message
> - move ptdump_pgtable_first_level() into pgalloc.h
> - skip the huge pud operation when CONFIG_X86_DIRECT_GBPAGES is disabled
> - docuemtns compile-time folded page table
> - drop the applied patch.
> - Link to RFC v2: https://lore.kernel.org/all/20260722-dummy_ptxp3-v2-0-d9e4bad31e0a@arm.com/
>
> from RFC v1 to RFC v2:
> - Restore slient fallback to next pXd in set_pXd() and pXd_pgtable()
> and add check whether they're called with dummy entry.
> - Add some comment for returning first entry of pgd in arm with
> 2 pgtable-level
> - Link to RFC v1: https://lore.kernel.org/all/20260713135614.1618183-1-yeoreum.yun@arm.com/
>
> ---
> Dave Hansen (1):
> x86/mm: Introduce helper for checking direct map 1G page support
>
> David Hildenbrand (Arm) (13):
> ARM: mm: make nommu pgd_t a scalar
> ARM: mm: make 2-level pgd_t a scalar
> ARM: mm: remove custom pgdp_get()
> LoongArch: mm: define pud_leaf() only when PUD exists
> MIPS: mm: define pud_leaf() only when PUD exists
> mm/pgtable: define (pgd|p4d|pud)_leaf() for folded page tables
> mm/pgtable: define (pgd|p4d|pud)_offset_lockless() for folded page tables
> openrisc/pgtable: drop __pmd_offset()
> mm/pgtable: optimize pmdp_get() and friends for folded pagetable levels
> mm/pgtable: catch abuse of folded dummy pgd_t/p4d_t/pud_t
> mm/pgtable: disallow calling (pgd|p4d|pud)_page, pgd_page_vaddr() and (p4d|pud)_pgtable with dummy
> mm/pgtable: disallow calling folded set_pgd/set_p4d/set_pud with dummy
> Documentation: mm: clarify behaviour of compile-time folded page tables
>
> Yeoreum Yun (7):
> mm: vmscan: remove stack copy address of pud/pmd pass in walk_pud/pmd_range()
> loongarch: kvm: remove stack copy address of pXd in pXd_offset()
> riscv: kvm: remove stack copy address of pXd in pXd_offset()
> riscv: mm: use proper set_pXd() for generic compile-time folded patable in vmalloc_fault()
> mm/pgtable: redefine PGTABLE_LEVEL enum with ascend order from PGD
> x86: mm: use pgtable_level enum in effective_prot_pXd()
> x86: mm: carve out the generic compile-time folded pgtable case in effective_prot()
>
> Documentation/mm/page_tables.rst | 84 +++++++++++++++++++++++++----
> arch/arm/include/asm/page-nommu.h | 4 +-
> arch/arm/include/asm/pgtable-2level-types.h | 20 +++++--
> arch/arm/include/asm/pgtable.h | 2 -
> arch/arm64/include/asm/pgtable.h | 23 --------
> arch/loongarch/include/asm/pgtable.h | 2 +
> arch/loongarch/kvm/mmu.c | 20 ++++---
> arch/mips/include/asm/pgtable.h | 2 +
> arch/openrisc/include/asm/pgtable.h | 3 --
> arch/riscv/kvm/mmu.c | 20 ++++---
> arch/riscv/mm/fault.c | 52 +++++++++++-------
> arch/x86/include/asm/pgtable.h | 14 +++++
> arch/x86/kernel/cpu/common.c | 2 +-
> arch/x86/kernel/machine_kexec_64.c | 2 +-
> arch/x86/mm/dump_pagetables.c | 18 ++++---
> arch/x86/mm/init.c | 2 +-
> arch/x86/mm/pat/set_memory.c | 6 +--
> include/asm-generic/pgtable-nop4d.h | 54 +++++++++++++++----
> include/asm-generic/pgtable-nopmd.h | 54 +++++++++++++++----
> include/asm-generic/pgtable-nopud.h | 56 +++++++++++++++----
> include/linux/pgtable.h | 69 +++++++++++++++++-------
> mm/vmscan.c | 4 +-
> 22 files changed, 371 insertions(+), 142 deletions(-)
> ---
> base-commit: 8d61431ed2607386b427752505379536eb634ce8
> change-id: 20260722-dummy_ptxp3-3741d78cc70f
>
> Best regards,
--
Thanks,
Usama
^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2026-09-21 21:12 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-21 10:55 [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
2026-09-21 10:55 ` [PATCH 01/21] ARM: mm: make nommu pgd_t a scalar Yeoreum Yun
2026-09-21 10:55 ` [PATCH 02/21] ARM: mm: make 2-level " Yeoreum Yun
2026-09-21 10:55 ` [PATCH 03/21] ARM: mm: remove custom pgdp_get() Yeoreum Yun
2026-09-21 10:55 ` [PATCH 04/21] LoongArch: mm: define pud_leaf() only when PUD exists Yeoreum Yun
2026-09-21 10:55 ` [PATCH 05/21] MIPS: " Yeoreum Yun
2026-09-21 10:55 ` [PATCH 06/21] mm/pgtable: define (pgd|p4d|pud)_leaf() for folded page tables Yeoreum Yun
2026-09-21 10:55 ` [PATCH 07/21] mm/pgtable: define (pgd|p4d|pud)_offset_lockless() " Yeoreum Yun
2026-09-21 10:55 ` [PATCH 08/21] mm: vmscan: remove stack copy address of pud/pmd pass in walk_pud/pmd_range() Yeoreum Yun
2026-09-21 10:55 ` [PATCH 09/21] loongarch: kvm: remove stack copy address of pXd in pXd_offset() Yeoreum Yun
2026-09-21 10:55 ` [PATCH 10/21] riscv: " Yeoreum Yun
2026-09-21 10:55 ` [PATCH 11/21] riscv: mm: use proper set_pXd() for generic compile-time folded patable in vmalloc_fault() Yeoreum Yun
2026-09-21 10:55 ` [PATCH 12/21] mm/pgtable: redefine PGTABLE_LEVEL enum with ascend order from PGD Yeoreum Yun
2026-09-21 10:55 ` [PATCH 13/21] x86/mm: Introduce helper for checking direct map 1G page support Yeoreum Yun
2026-09-21 10:55 ` [PATCH 14/21] x86: mm: use pgtable_level enum in effective_prot_pXd() Yeoreum Yun
2026-09-21 10:55 ` [PATCH 15/21] x86: mm: carve out the generic compile-time folded pgtable case in effective_prot() Yeoreum Yun
2026-09-21 10:55 ` [PATCH 16/21] openrisc/pgtable: drop __pmd_offset() Yeoreum Yun
2026-09-21 10:55 ` [PATCH 17/21] mm/pgtable: optimize pmdp_get() and friends for folded pagetable levels Yeoreum Yun
2026-09-21 10:55 ` [PATCH 18/21] mm/pgtable: catch abuse of folded dummy pgd_t/p4d_t/pud_t Yeoreum Yun
2026-09-21 10:55 ` [PATCH 19/21] mm/pgtable: disallow calling (pgd|p4d|pud)_page, pgd_page_vaddr() and (p4d|pud)_pgtable with dummy Yeoreum Yun
2026-09-21 10:55 ` [PATCH 20/21] mm/pgtable: disallow calling folded set_pgd/set_p4d/set_pud " Yeoreum Yun
2026-09-21 10:55 ` [PATCH 21/21] Documentation: mm: clarify behaviour of compile-time folded page tables Yeoreum Yun
2026-09-21 16:20 ` Randy Dunlap
2026-09-21 20:26 ` Yeoreum Yun
2026-09-21 21:11 ` [PATCH 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Muhammad Usama Anjum
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®