* [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable
@ 2026-09-02 11:56 Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 01/21] ARM: mm: make nommu pgd_t a scalar Yeoreum Yun
` (20 more replies)
0 siblings, 21 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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
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 |
...
Patch History
=============
from v2 to 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.
- https://lore.kernel.org/all/20260722-dummy_ptxp3-v2-0-d9e4bad31e0a@arm.com/
from v1 to 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
- https://lore.kernel.org/all/20260713135614.1618183-1-yeoreum.yun@arm.com/
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
---
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 (8):
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()
x86: mm: skip collapse_pud_page() when CONFIG_X86_DIRECT_GBPAGES disabled
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/mm/dump_pagetables.c | 18 ++++---
arch/x86/mm/pat/set_memory.c | 2 +-
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 +-
18 files changed, 352 insertions(+), 137 deletions(-)
---
base-commit: e3b5239afe1b8f0194db7436b17c33e94c1988c4
change-id: 20260722-dummy_ptxp3-3741d78cc70f
Best regards,
--
Sincerely,
Yeoreum Yun
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH RFC v3 01/21] ARM: mm: make nommu pgd_t a scalar
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 02/21] ARM: mm: make 2-level " Yeoreum Yun
` (19 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 e74415c959be..88659b38e236 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 02/21] ARM: mm: make 2-level pgd_t a scalar
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 01/21] ARM: mm: make nommu pgd_t a scalar Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 03/21] ARM: mm: remove custom pgdp_get() Yeoreum Yun
` (18 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 650e793f4142..805044ea315b 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 03/21] ARM: mm: remove custom pgdp_get()
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 01/21] ARM: mm: make nommu pgd_t a scalar Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 02/21] ARM: mm: make 2-level " Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 04/21] LoongArch: mm: define pud_leaf() only when PUD exists Yeoreum Yun
` (17 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 8dd17d20faa3..ff3868acea94 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 04/21] LoongArch: mm: define pud_leaf() only when PUD exists
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (2 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 03/21] ARM: mm: remove custom pgdp_get() Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 05/21] MIPS: " Yeoreum Yun
` (16 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 cf29a4c8ac59..8aee4fc27a26 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 05/21] MIPS: mm: define pud_leaf() only when PUD exists
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (3 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 04/21] LoongArch: mm: define pud_leaf() only when PUD exists Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 06/21] mm/pgtable: define (pgd|p4d|pud)_leaf() for folded page tables Yeoreum Yun
` (15 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 fa7b935f947c..151f4d15bd12 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 06/21] mm/pgtable: define (pgd|p4d|pud)_leaf() for folded page tables
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (4 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 05/21] MIPS: " Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 12:15 ` sashiko-bot
2026-09-02 11:56 ` [PATCH RFC v3 07/21] mm/pgtable: define (pgd|p4d|pud)_offset_lockless() " Yeoreum Yun
` (14 subsequent siblings)
20 siblings, 1 reply; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 1cf739ee38aa..c6a5a43899b5 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 ff4235cf84d7..4e5aaf253b6a 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 eedee8e3ad68..6c9bca78047c 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 07/21] mm/pgtable: define (pgd|p4d|pud)_offset_lockless() for folded page tables
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (5 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 06/21] mm/pgtable: define (pgd|p4d|pud)_leaf() for folded page tables Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 08/21] mm: vmscan: remove stack copy address of pud/pmd pass in walk_pud/pmd_range() Yeoreum Yun
` (13 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 e89ec5f4787b..a3c882e46777 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 c6a5a43899b5..019c3f074b77 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 4e5aaf253b6a..1dd5b165234b 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 6c9bca78047c..5a2b0a81ae19 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 08/21] mm: vmscan: remove stack copy address of pud/pmd pass in walk_pud/pmd_range()
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (6 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 07/21] mm/pgtable: define (pgd|p4d|pud)_offset_lockless() " Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 09/21] loongarch: kvm: remove stack copy address of pXd in pXd_offset() Yeoreum Yun
` (12 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 4d51b0d8e287..4e98088becab 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -3777,7 +3777,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]++;
@@ -3813,7 +3813,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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 09/21] loongarch: kvm: remove stack copy address of pXd in pXd_offset()
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (7 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 08/21] mm: vmscan: remove stack copy address of pud/pmd pass in walk_pud/pmd_range() Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 12:19 ` sashiko-bot
2026-09-02 11:56 ` [PATCH RFC v3 10/21] riscv: " Yeoreum Yun
` (11 subsequent siblings)
20 siblings, 1 reply; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 e104897aa532..837b40bb694f 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 10/21] riscv: kvm: remove stack copy address of pXd in pXd_offset()
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (8 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 09/21] loongarch: kvm: remove stack copy address of pXd in pXd_offset() Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 11/21] riscv: mm: use proper set_pXd() for generic compile-time folded patable in vmalloc_fault() Yeoreum Yun
` (10 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 6035b5ec9503..dd5a7b0bd084 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 11/21] riscv: mm: use proper set_pXd() for generic compile-time folded patable in vmalloc_fault()
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (9 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 10/21] riscv: " Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 12/21] mm/pgtable: redefine PGTABLE_LEVEL enum with ascend order from PGD Yeoreum Yun
` (9 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 04ed6f8acae4..b2bcaf10d13f 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 12/21] mm/pgtable: redefine PGTABLE_LEVEL enum with ascend order from PGD
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (10 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 11/21] riscv: mm: use proper set_pXd() for generic compile-time folded patable in vmalloc_fault() Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 13/21] x86: mm: use pgtable_level enum in effective_prot_pXd() Yeoreum Yun
` (8 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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.
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 e3c8ab96941c..3186096a6e13 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 13/21] x86: mm: use pgtable_level enum in effective_prot_pXd()
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (11 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 12/21] mm/pgtable: redefine PGTABLE_LEVEL enum with ascend order from PGD Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 20:48 ` Dave Hansen
2026-09-02 11:56 ` [PATCH RFC v3 14/21] x86: mm: carve out the generic compile-time folded pgtable case in effective_prot() Yeoreum Yun
` (7 subsequent siblings)
20 siblings, 1 reply; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 integer in effective_prot_pXd(), use
pgtable level enum.
There should be no functional change.
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 2afa7a23340e..a18a61e732c3 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 14/21] x86: mm: carve out the generic compile-time folded pgtable case in effective_prot()
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (12 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 13/21] x86: mm: use pgtable_level enum in effective_prot_pXd() Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 20:46 ` Dave Hansen
2026-09-02 11:56 ` [PATCH RFC v3 15/21] x86: mm: skip collapse_pud_page() when CONFIG_X86_DIRECT_GBPAGES disabled Yeoreum Yun
` (6 subsequent siblings)
20 siblings, 1 reply; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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.
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 a18a61e732c3..2acbe41eb58f 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 3186096a6e13..ed7101a13ce9 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 15/21] x86: mm: skip collapse_pud_page() when CONFIG_X86_DIRECT_GBPAGES disabled
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (13 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 14/21] x86: mm: carve out the generic compile-time folded pgtable case in effective_prot() Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 12:17 ` sashiko-bot
2026-09-02 15:38 ` Dave Hansen
2026-09-02 11:56 ` [PATCH RFC v3 16/21] openrisc/pgtable: drop __pmd_offset() Yeoreum Yun
` (5 subsequent siblings)
20 siblings, 2 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 pXd_page() will change with generic compile-time folded
page tables by disallowing its use and triggering a compile-time error
when it's used improperly, ensuring that the actual pXd_page() is used
instead.
To prepare fot that, skip collapse_pud_page() when
CONFIG_X86_DIRECT_GBPAGES is disabled.
There should be no functional change.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
arch/x86/mm/pat/set_memory.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
index a1a061d995b3..07a873775279 100644
--- a/arch/x86/mm/pat/set_memory.c
+++ b/arch/x86/mm/pat/set_memory.c
@@ -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 (!IS_ENABLED(CONFIG_X86_FEATURE_GBPAGES) || !direct_gbpages)
return 0;
addr &= PUD_MASK;
--
2.43.0
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 16/21] openrisc/pgtable: drop __pmd_offset()
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (14 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 15/21] x86: mm: skip collapse_pud_page() when CONFIG_X86_DIRECT_GBPAGES disabled Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 17/21] mm/pgtable: optimize pmdp_get() and friends for folded pagetable levels Yeoreum Yun
` (4 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 13afcc0bd863..7fceed641610 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 17/21] mm/pgtable: optimize pmdp_get() and friends for folded pagetable levels
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (15 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 16/21] openrisc/pgtable: drop __pmd_offset() Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 18/21] mm/pgtable: catch abuse of folded dummy pgd_t/p4d_t/pud_t Yeoreum Yun
` (3 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 019c3f074b77..acd62ee23353 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 1dd5b165234b..9322f07ddf1e 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 5a2b0a81ae19..8f01abbb0050 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 18/21] mm/pgtable: catch abuse of folded dummy pgd_t/p4d_t/pud_t
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (16 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 17/21] mm/pgtable: optimize pmdp_get() and friends for folded pagetable levels Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 19/21] mm/pgtable: disallow calling (pgd|p4d|pud)_page, pgd_page_vaddr() and (p4d|pud)_pgtable with dummy Yeoreum Yun
` (2 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 acd62ee23353..2d86325235da 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 9322f07ddf1e..bd40d3a5743f 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 8f01abbb0050..7475d0bd0f2e 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 19/21] mm/pgtable: disallow calling (pgd|p4d|pud)_page, pgd_page_vaddr() and (p4d|pud)_pgtable with dummy
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (17 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 18/21] mm/pgtable: catch abuse of folded dummy pgd_t/p4d_t/pud_t Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 20/21] mm/pgtable: disallow calling folded set_pgd/set_p4d/set_pud " Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 21/21] Documentation: mm: clarify behaviour of compile-time folded page tables Yeoreum Yun
20 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 2d86325235da..d2dccf7542da 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 bd40d3a5743f..2afbf2d8659d 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 7475d0bd0f2e..3264673c0c38 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 20/21] mm/pgtable: disallow calling folded set_pgd/set_p4d/set_pud with dummy
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (18 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 19/21] mm/pgtable: disallow calling (pgd|p4d|pud)_page, pgd_page_vaddr() and (p4d|pud)_pgtable with dummy Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 21/21] Documentation: mm: clarify behaviour of compile-time folded page tables Yeoreum Yun
20 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 d2dccf7542da..12b01768134b 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 2afbf2d8659d..11b04c107129 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 3264673c0c38..5ee8f1852cd8 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 related [flat|nested] 31+ messages in thread
* [PATCH RFC v3 21/21] Documentation: mm: clarify behaviour of compile-time folded page tables
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
` (19 preceding siblings ...)
2026-09-02 11:56 ` [PATCH RFC v3 20/21] mm/pgtable: disallow calling folded set_pgd/set_p4d/set_pud " Yeoreum Yun
@ 2026-09-02 11:56 ` Yeoreum Yun
20 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 11:56 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 126c87628250..84f2715c7de0 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 related [flat|nested] 31+ messages in thread
* Re: [PATCH RFC v3 06/21] mm/pgtable: define (pgd|p4d|pud)_leaf() for folded page tables
2026-09-02 11:56 ` [PATCH RFC v3 06/21] mm/pgtable: define (pgd|p4d|pud)_leaf() for folded page tables Yeoreum Yun
@ 2026-09-02 12:15 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-09-02 12:15 UTC (permalink / raw)
To: Yeoreum Yun; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The patch accidentally resurrects the `p4d_ERROR` and `pud_ERROR` macros, which reference a non-existent `pgd_ERROR` macro.
--
commit 1ad6d2e7fa6f4d648ec4866410881fd66f3c3298
Author: David Hildenbrand (Arm) <david@kernel.org>
mm/pgtable: define (pgd|p4d|pud)_leaf() for folded page tables
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.
> 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))
[Severity: Low]
Does this resurrect a broken macro? pgd_ERROR does not appear to exist in the
codebase anymore, so if a developer attempts to use p4d_ERROR in the future,
would it result in a build failure due to an undefined symbol?
[ ... ]
> 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))
[Severity: Low]
Since p4d_ERROR relies on the non-existent pgd_ERROR as noted above, does this
also mean pud_ERROR is broken in the same way?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260902-dummy_ptxp3-v3-0-5d8f5b17c25c@arm.com?part=6
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH RFC v3 15/21] x86: mm: skip collapse_pud_page() when CONFIG_X86_DIRECT_GBPAGES disabled
2026-09-02 11:56 ` [PATCH RFC v3 15/21] x86: mm: skip collapse_pud_page() when CONFIG_X86_DIRECT_GBPAGES disabled Yeoreum Yun
@ 2026-09-02 12:17 ` sashiko-bot
2026-09-02 12:29 ` Yeoreum Yun
2026-09-02 15:38 ` Dave Hansen
1 sibling, 1 reply; 31+ messages in thread
From: sashiko-bot @ 2026-09-02 12:17 UTC (permalink / raw)
To: Yeoreum Yun; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Incorrect Kconfig macro name `CONFIG_X86_FEATURE_GBPAGES` unconditionally disables PUD page collapsing on x86.
--
commit e72cd2f328b1fab1c51fad6dcdfc5273b0764f4b
Author: Yeoreum Yun <yeoreum.yun@arm.com>
x86: mm: skip collapse_pud_page() when CONFIG_X86_DIRECT_GBPAGES disabled
This commit skips collapse_pud_page() when gbpages are disabled to prepare
for compile-time folded page table changes.
> diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
> index a1a061d995b31..07a873775279f 100644
> --- a/arch/x86/mm/pat/set_memory.c
> +++ b/arch/x86/mm/pat/set_memory.c
> @@ -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 (!IS_ENABLED(CONFIG_X86_FEATURE_GBPAGES) || !direct_gbpages)
[Severity: High]
Does CONFIG_X86_FEATURE_GBPAGES exist as a Kconfig option? The commit
message mentions CONFIG_X86_DIRECT_GBPAGES, so it looks like the Kconfig
macro might have been mixed up with the CPU feature flag X86_FEATURE_GBPAGES.
Because this Kconfig option does not exist, IS_ENABLED() will resolve to 0,
making the condition unconditionally true. Will this completely disable PUD
page collapsing on x86, preventing 1GB huge pages from being collapsed in
the kernel direct map?
> return 0;
>
> addr &= PUD_MASK;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260902-dummy_ptxp3-v3-0-5d8f5b17c25c@arm.com?part=15
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH RFC v3 09/21] loongarch: kvm: remove stack copy address of pXd in pXd_offset()
2026-09-02 11:56 ` [PATCH RFC v3 09/21] loongarch: kvm: remove stack copy address of pXd in pXd_offset() Yeoreum Yun
@ 2026-09-02 12:19 ` sashiko-bot
2026-09-02 12:38 ` Yeoreum Yun
0 siblings, 1 reply; 31+ messages in thread
From: sashiko-bot @ 2026-09-02 12:19 UTC (permalink / raw)
To: Yeoreum Yun; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing `pud_leaf()` / huge page check before traversing to PMD level, causing invalid memory dereference on 1GB huge pages.
--
commit 7df2ea4ead6f791e1840ca23d67765ca06e93e1b
Author: Yeoreum Yun <yeoreum.yun@arm.com>
loongarch: kvm: remove stack copy address of pXd in pXd_offset()
This commit refactors host_pfn_mapping_level() to prepare for generic
compile-time folded page tables. It replaces direct uses of stack-based pXd
values with pXd_offset_lockless(), passing the pointers directly.
> 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
[ ... ]
> @@ -698,19 +698,23 @@ static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn,
[ ... ]
> - 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);
[Severity: High]
This is a pre-existing issue, but does this code need a check to see if the
PUD is a leaf entry before stepping down to the PMD level?
In arch/loongarch/kvm/mmu.c:host_pfn_mapping_level(), the code reads the PUD
entry and verifies that it is present, but it does not check if it is a 1GB
huge page leaf entry before traversing to the PMD level.
If a guest memory region is backed by a 1GB huge page on the host, the PUD
entry will contain a PFN-encoded value and metadata flags. By unconditionally
passing this to pmd_offset_lockless(), the macro may interpret the PFN encoded
value as a kernel virtual address directory pointer. This produces a bogus
pointer that pmdp_get() will then dereference, causing an invalid memory
dereference and potentially crashing the host.
Could a pud_leaf() or kvm_pte_huge(pud_val(pud)) check be added before the
pmd_offset_lockless() call to prevent this crash when 1GB huge pages are
used?
> if (pmd_none(pmd) || !pmd_present(pmd))
> goto out;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260902-dummy_ptxp3-v3-0-5d8f5b17c25c@arm.com?part=9
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH RFC v3 15/21] x86: mm: skip collapse_pud_page() when CONFIG_X86_DIRECT_GBPAGES disabled
2026-09-02 12:17 ` sashiko-bot
@ 2026-09-02 12:29 ` Yeoreum Yun
0 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 12:29 UTC (permalink / raw)
To: sashiko-reviews; +Cc: Yeoreum Yun, kvm
On Wed, Sep 02, 2026 at 12:17:21PM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] Incorrect Kconfig macro name `CONFIG_X86_FEATURE_GBPAGES` unconditionally disables PUD page collapsing on x86.
> --
>
> commit e72cd2f328b1fab1c51fad6dcdfc5273b0764f4b
> Author: Yeoreum Yun <yeoreum.yun@arm.com>
>
> x86: mm: skip collapse_pud_page() when CONFIG_X86_DIRECT_GBPAGES disabled
>
> This commit skips collapse_pud_page() when gbpages are disabled to prepare
> for compile-time folded page table changes.
>
> > diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
> > index a1a061d995b31..07a873775279f 100644
> > --- a/arch/x86/mm/pat/set_memory.c
> > +++ b/arch/x86/mm/pat/set_memory.c
> > @@ -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 (!IS_ENABLED(CONFIG_X86_FEATURE_GBPAGES) || !direct_gbpages)
>
> [Severity: High]
> Does CONFIG_X86_FEATURE_GBPAGES exist as a Kconfig option? The commit
> message mentions CONFIG_X86_DIRECT_GBPAGES, so it looks like the Kconfig
> macro might have been mixed up with the CPU feature flag X86_FEATURE_GBPAGES.
>
> Because this Kconfig option does not exist, IS_ENABLED() will resolve to 0,
> making the condition unconditionally true. Will this completely disable PUD
> page collapsing on x86, preventing 1GB huge pages from being collapsed in
> the kernel direct map?
Sorry for typo. I'll change into CONFIG_X86_DIRECT_GBPAGES in next
round.
--
Sincerely,
Yeoreum Yun
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH RFC v3 09/21] loongarch: kvm: remove stack copy address of pXd in pXd_offset()
2026-09-02 12:19 ` sashiko-bot
@ 2026-09-02 12:38 ` Yeoreum Yun
0 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 12:38 UTC (permalink / raw)
To: sashiko-reviews; +Cc: Yeoreum Yun, kvm
On Wed, Sep 02, 2026 at 12:19:12PM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] Missing `pud_leaf()` / huge page check before traversing to PMD level, causing invalid memory dereference on 1GB huge pages.
> --
>
> commit 7df2ea4ead6f791e1840ca23d67765ca06e93e1b
> Author: Yeoreum Yun <yeoreum.yun@arm.com>
>
> loongarch: kvm: remove stack copy address of pXd in pXd_offset()
>
> This commit refactors host_pfn_mapping_level() to prepare for generic
> compile-time folded page tables. It replaces direct uses of stack-based pXd
> values with pXd_offset_lockless(), passing the pointers directly.
>
> > 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
> [ ... ]
> > @@ -698,19 +698,23 @@ static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn,
> [ ... ]
> > - 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);
>
> [Severity: High]
> This is a pre-existing issue, but does this code need a check to see if the
> PUD is a leaf entry before stepping down to the PMD level?
>
> In arch/loongarch/kvm/mmu.c:host_pfn_mapping_level(), the code reads the PUD
> entry and verifies that it is present, but it does not check if it is a 1GB
> huge page leaf entry before traversing to the PMD level.
>
> If a guest memory region is backed by a 1GB huge page on the host, the PUD
> entry will contain a PFN-encoded value and metadata flags. By unconditionally
> passing this to pmd_offset_lockless(), the macro may interpret the PFN encoded
> value as a kernel virtual address directory pointer. This produces a bogus
> pointer that pmdp_get() will then dereference, causing an invalid memory
> dereference and potentially crashing the host.
>
> Could a pud_leaf() or kvm_pte_huge(pud_val(pud)) check be added before the
> pmd_offset_lockless() call to prevent this crash when 1GB huge pages are
> used?
>
> > if (pmd_none(pmd) || !pmd_present(pmd))
> > goto out;
AFAIK, loongarch doesn't create the pud block mapping. so it seems
ignoralbe.
--
Sincerely,
Yeoreum Yun
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH RFC v3 15/21] x86: mm: skip collapse_pud_page() when CONFIG_X86_DIRECT_GBPAGES disabled
2026-09-02 11:56 ` [PATCH RFC v3 15/21] x86: mm: skip collapse_pud_page() when CONFIG_X86_DIRECT_GBPAGES disabled Yeoreum Yun
2026-09-02 12:17 ` sashiko-bot
@ 2026-09-02 15:38 ` Dave Hansen
2026-09-02 16:48 ` Yeoreum Yun
1 sibling, 1 reply; 31+ messages in thread
From: Dave Hansen @ 2026-09-02 15:38 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
[-- Attachment #1: Type: text/plain, Size: 1296 bytes --]
On 9/2/26 04:56, Yeoreum Yun wrote:
> The behaviour of pXd_page() will change with generic compile-time folded
> page tables by disallowing its use and triggering a compile-time error
> when it's used improperly, ensuring that the actual pXd_page() is used
> instead.
>
> To prepare fot that, skip collapse_pud_page() when
> CONFIG_X86_DIRECT_GBPAGES is disabled.
Nit: this doesn't explain how the change actually fixes anything or what
the specific problem being solved is.
I think you want to say something along the lines of:
collapse_pud_page() uses pud_page() in a way which will soon
trigger a compile-time error on configs that have a folded pud.
The code which will generate that error is actually unreachable
on those configs because 'direct_gbpages' is always 0 there.
However, the compiler does not know that because
'direct_gbpages' is a normal integer from a separate compilation
unit.
Make the compiler aware when most of collapse_pud_page() is
unreachable by adding a Kconfig check. This ensures it will not
trip the errors when they are introduced. It probably also trims
the kernel image down a wee bit too as a side benefit.
Maybe I should just merge something like the attached patch. I think it
would solve your problem and make things generally cleaner too.
[-- Attachment #2: direct_gbpages-compiletime.patch --]
[-- Type: text/x-patch, Size: 4323 bytes --]
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 this
prevents compiler optimization in cases where 1G mappings are
compile-time disabled (via X86_DIRECT_GBPAGES).
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
away.
---
b/arch/x86/include/asm/pgtable.h | 14 ++++++++++++++
b/arch/x86/kernel/cpu/common.c | 2 +-
b/arch/x86/kernel/machine_kexec_64.c | 2 +-
b/arch/x86/mm/init.c | 2 +-
b/arch/x86/mm/pat/set_memory.c | 4 ++--
5 files changed, 19 insertions(+), 5 deletions(-)
diff -puN arch/x86/include/asm/pgtable.h~direct_gbpages-compiletime arch/x86/include/asm/pgtable.h
--- a/arch/x86/include/asm/pgtable.h~direct_gbpages-compiletime 2026-09-02 06:53:57.835733398 -0700
+++ b/arch/x86/include/asm/pgtable.h 2026-09-02 08:17:01.434727771 -0700
@@ -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 (!cpu_feature_enabled(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 -puN arch/x86/mm/init.c~direct_gbpages-compiletime arch/x86/mm/init.c
--- a/arch/x86/mm/init.c~direct_gbpages-compiletime 2026-09-02 06:55:01.004094924 -0700
+++ b/arch/x86/mm/init.c 2026-09-02 08:20:36.759992562 -0700
@@ -251,7 +251,7 @@ static void __init probe_page_size_mask(
__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 -puN arch/x86/kernel/cpu/common.c~direct_gbpages-compiletime arch/x86/kernel/cpu/common.c
--- a/arch/x86/kernel/cpu/common.c~direct_gbpages-compiletime 2026-09-02 06:57:47.935849397 -0700
+++ b/arch/x86/kernel/cpu/common.c 2026-09-02 06:57:57.299617535 -0700
@@ -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 -puN arch/x86/kernel/machine_kexec_64.c~direct_gbpages-compiletime arch/x86/kernel/machine_kexec_64.c
--- a/arch/x86/kernel/machine_kexec_64.c~direct_gbpages-compiletime 2026-09-02 06:57:58.462712975 -0700
+++ b/arch/x86/kernel/machine_kexec_64.c 2026-09-02 06:58:05.219267514 -0700
@@ -257,7 +257,7 @@ static int init_pgtable(struct kimage *i
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 -puN arch/x86/mm/pat/set_memory.c~direct_gbpages-compiletime arch/x86/mm/pat/set_memory.c
--- a/arch/x86/mm/pat/set_memory.c~direct_gbpages-compiletime 2026-09-02 06:58:43.518414555 -0700
+++ b/arch/x86/mm/pat/set_memory.c 2026-09-02 06:59:27.252015369 -0700
@@ -130,7 +130,7 @@ void arch_report_meminfo(struct seq_file
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);
}
@@ -1340,7 +1340,7 @@ static int collapse_pud_page(pud_t *pud,
pmd_t *pmd, first;
int i;
- if (!direct_gbpages)
+ if (!direct_gbpages_enabled())
return 0;
addr &= PUD_MASK;
_
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH RFC v3 15/21] x86: mm: skip collapse_pud_page() when CONFIG_X86_DIRECT_GBPAGES disabled
2026-09-02 15:38 ` Dave Hansen
@ 2026-09-02 16:48 ` Yeoreum Yun
0 siblings, 0 replies; 31+ messages in thread
From: Yeoreum Yun @ 2026-09-02 16:48 UTC (permalink / raw)
To: Dave Hansen
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 Dave,
> On 9/2/26 04:56, Yeoreum Yun wrote:
> > The behaviour of pXd_page() will change with generic compile-time folded
> > page tables by disallowing its use and triggering a compile-time error
> > when it's used improperly, ensuring that the actual pXd_page() is used
> > instead.
> >
> > To prepare fot that, skip collapse_pud_page() when
> > CONFIG_X86_DIRECT_GBPAGES is disabled.
>
> Nit: this doesn't explain how the change actually fixes anything or what
> the specific problem being solved is.
>
> I think you want to say something along the lines of:
>
> collapse_pud_page() uses pud_page() in a way which will soon
> trigger a compile-time error on configs that have a folded pud.
>
> The code which will generate that error is actually unreachable
> on those configs because 'direct_gbpages' is always 0 there.
> However, the compiler does not know that because
> 'direct_gbpages' is a normal integer from a separate compilation
> unit.
>
> Make the compiler aware when most of collapse_pud_page() is
> unreachable by adding a Kconfig check. This ensures it will not
> trip the errors when they are introduced. It probably also trims
> the kernel image down a wee bit too as a side benefit.
Yes.. Sorry for my poor commit message.
>
> Maybe I should just merge something like the attached patch. I think it
> would solve your problem and make things generally cleaner too.
>
> 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 this
> prevents compiler optimization in cases where 1G mappings are
> compile-time disabled (via X86_DIRECT_GBPAGES).
>
> 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
> away.
Yeap. I've tested with your patch and it works for me!
Thanks!
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Tested-by: Yeoreum Yun <yeoreum.yun@arm.com>
>
> ---
>
> b/arch/x86/include/asm/pgtable.h | 14 ++++++++++++++
> b/arch/x86/kernel/cpu/common.c | 2 +-
> b/arch/x86/kernel/machine_kexec_64.c | 2 +-
> b/arch/x86/mm/init.c | 2 +-
> b/arch/x86/mm/pat/set_memory.c | 4 ++--
> 5 files changed, 19 insertions(+), 5 deletions(-)
>
> diff -puN arch/x86/include/asm/pgtable.h~direct_gbpages-compiletime arch/x86/include/asm/pgtable.h
> --- a/arch/x86/include/asm/pgtable.h~direct_gbpages-compiletime 2026-09-02 06:53:57.835733398 -0700
> +++ b/arch/x86/include/asm/pgtable.h 2026-09-02 08:17:01.434727771 -0700
> @@ -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 (!cpu_feature_enabled(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 -puN arch/x86/mm/init.c~direct_gbpages-compiletime arch/x86/mm/init.c
> --- a/arch/x86/mm/init.c~direct_gbpages-compiletime 2026-09-02 06:55:01.004094924 -0700
> +++ b/arch/x86/mm/init.c 2026-09-02 08:20:36.759992562 -0700
> @@ -251,7 +251,7 @@ static void __init probe_page_size_mask(
> __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 -puN arch/x86/kernel/cpu/common.c~direct_gbpages-compiletime arch/x86/kernel/cpu/common.c
> --- a/arch/x86/kernel/cpu/common.c~direct_gbpages-compiletime 2026-09-02 06:57:47.935849397 -0700
> +++ b/arch/x86/kernel/cpu/common.c 2026-09-02 06:57:57.299617535 -0700
> @@ -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 -puN arch/x86/kernel/machine_kexec_64.c~direct_gbpages-compiletime arch/x86/kernel/machine_kexec_64.c
> --- a/arch/x86/kernel/machine_kexec_64.c~direct_gbpages-compiletime 2026-09-02 06:57:58.462712975 -0700
> +++ b/arch/x86/kernel/machine_kexec_64.c 2026-09-02 06:58:05.219267514 -0700
> @@ -257,7 +257,7 @@ static int init_pgtable(struct kimage *i
> 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 -puN arch/x86/mm/pat/set_memory.c~direct_gbpages-compiletime arch/x86/mm/pat/set_memory.c
> --- a/arch/x86/mm/pat/set_memory.c~direct_gbpages-compiletime 2026-09-02 06:58:43.518414555 -0700
> +++ b/arch/x86/mm/pat/set_memory.c 2026-09-02 06:59:27.252015369 -0700
> @@ -130,7 +130,7 @@ void arch_report_meminfo(struct seq_file
> 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);
> }
> @@ -1340,7 +1340,7 @@ static int collapse_pud_page(pud_t *pud,
> pmd_t *pmd, first;
> int i;
>
> - if (!direct_gbpages)
> + if (!direct_gbpages_enabled())
> return 0;
>
> addr &= PUD_MASK;
> _
--
Sincerely,
Yeoreum Yun
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH RFC v3 14/21] x86: mm: carve out the generic compile-time folded pgtable case in effective_prot()
2026-09-02 11:56 ` [PATCH RFC v3 14/21] x86: mm: carve out the generic compile-time folded pgtable case in effective_prot() Yeoreum Yun
@ 2026-09-02 20:46 ` Dave Hansen
0 siblings, 0 replies; 31+ messages in thread
From: Dave Hansen @ 2026-09-02 20:46 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
Thanks for making those changes and adding the helper to generic code.
Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH RFC v3 13/21] x86: mm: use pgtable_level enum in effective_prot_pXd()
2026-09-02 11:56 ` [PATCH RFC v3 13/21] x86: mm: use pgtable_level enum in effective_prot_pXd() Yeoreum Yun
@ 2026-09-02 20:48 ` Dave Hansen
0 siblings, 0 replies; 31+ messages in thread
From: Dave Hansen @ 2026-09-02 20:48 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/2/26 04:56, Yeoreum Yun wrote:
> Instead of using hard-coded integer in effective_prot_pXd(), use
> pgtable level enum.
Does this actually *do* anything? ;)
I guess it's nice to have a wee bit of type safety from the enum and it
means that you don't have to *know* which level number a PUD is, for
example.
Either way:
Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
^ permalink raw reply [flat|nested] 31+ messages in thread
end of thread, other threads:[~2026-09-02 20:48 UTC | newest]
Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-02 11:56 [PATCH RFC v3 00/21] mm: change behavior of pXdp_get()/pXd_page() in compile-time folded pgtable Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 01/21] ARM: mm: make nommu pgd_t a scalar Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 02/21] ARM: mm: make 2-level " Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 03/21] ARM: mm: remove custom pgdp_get() Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 04/21] LoongArch: mm: define pud_leaf() only when PUD exists Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 05/21] MIPS: " Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 06/21] mm/pgtable: define (pgd|p4d|pud)_leaf() for folded page tables Yeoreum Yun
2026-09-02 12:15 ` sashiko-bot
2026-09-02 11:56 ` [PATCH RFC v3 07/21] mm/pgtable: define (pgd|p4d|pud)_offset_lockless() " Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 08/21] mm: vmscan: remove stack copy address of pud/pmd pass in walk_pud/pmd_range() Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 09/21] loongarch: kvm: remove stack copy address of pXd in pXd_offset() Yeoreum Yun
2026-09-02 12:19 ` sashiko-bot
2026-09-02 12:38 ` Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 10/21] riscv: " Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 11/21] riscv: mm: use proper set_pXd() for generic compile-time folded patable in vmalloc_fault() Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 12/21] mm/pgtable: redefine PGTABLE_LEVEL enum with ascend order from PGD Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 13/21] x86: mm: use pgtable_level enum in effective_prot_pXd() Yeoreum Yun
2026-09-02 20:48 ` Dave Hansen
2026-09-02 11:56 ` [PATCH RFC v3 14/21] x86: mm: carve out the generic compile-time folded pgtable case in effective_prot() Yeoreum Yun
2026-09-02 20:46 ` Dave Hansen
2026-09-02 11:56 ` [PATCH RFC v3 15/21] x86: mm: skip collapse_pud_page() when CONFIG_X86_DIRECT_GBPAGES disabled Yeoreum Yun
2026-09-02 12:17 ` sashiko-bot
2026-09-02 12:29 ` Yeoreum Yun
2026-09-02 15:38 ` Dave Hansen
2026-09-02 16:48 ` Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 16/21] openrisc/pgtable: drop __pmd_offset() Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 17/21] mm/pgtable: optimize pmdp_get() and friends for folded pagetable levels Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 18/21] mm/pgtable: catch abuse of folded dummy pgd_t/p4d_t/pud_t Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 19/21] mm/pgtable: disallow calling (pgd|p4d|pud)_page, pgd_page_vaddr() and (p4d|pud)_pgtable with dummy Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 20/21] mm/pgtable: disallow calling folded set_pgd/set_p4d/set_pud " Yeoreum Yun
2026-09-02 11:56 ` [PATCH RFC v3 21/21] Documentation: mm: clarify behaviour of compile-time folded page tables Yeoreum Yun
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox