[PATCH 3/3] mm: generalize PUD page table allocation
From: Muchun Song
Date: Tue Oct 13 2026 - 23:59:52 EST
The generic PUD allocator assumes order-0 page tables and zero-valued empty
entries. MIPS and LoongArch need pud_init() to install their invalid
entries. MIPS also uses PUD_TABLE_ORDER to describe the allocation size.
Default PUD_TABLE_ORDER to zero, honor architecture overrides, and invoke
pud_init() from the generic allocator. MIPS and LoongArch can then drop
their duplicate helpers and use the generic constructor handling and kernel
ptdesc marking.
This also switches their user PUD allocations from GFP_KERNEL to
GFP_PGTABLE_USER, so they are accounted to the active memory cgroup
context. Allocations for init_mm continue to use GFP_PGTABLE_KERNEL.
Assisted-by: LLM
Signed-off-by: Muchun Song <songmuchun@xxxxxxxxxxxxx>
---
arch/loongarch/include/asm/pgalloc.h | 16 ----------------
arch/mips/include/asm/pgalloc.h | 15 ---------------
include/asm-generic/pgalloc.h | 11 +++++++++--
3 files changed, 9 insertions(+), 33 deletions(-)
diff --git a/arch/loongarch/include/asm/pgalloc.h b/arch/loongarch/include/asm/pgalloc.h
index 1fc9a0751f19..06a36da302d3 100644
--- a/arch/loongarch/include/asm/pgalloc.h
+++ b/arch/loongarch/include/asm/pgalloc.h
@@ -8,7 +8,6 @@
#include <linux/mm.h>
#include <linux/sched.h>
-#define __HAVE_ARCH_PUD_ALLOC_ONE
#include <asm-generic/pgalloc.h>
static inline void pmd_populate_kernel(struct mm_struct *mm,
@@ -51,21 +50,6 @@ extern pgd_t *pgd_alloc(struct mm_struct *mm);
#endif
#ifndef __PAGETABLE_PUD_FOLDED
-
-static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
-{
- pud_t *pud;
- struct ptdesc *ptdesc = pagetable_alloc(GFP_KERNEL, 0);
-
- if (!ptdesc)
- return NULL;
- pagetable_pud_ctor(ptdesc);
- pud = ptdesc_address(ptdesc);
-
- pud_init(pud);
- return pud;
-}
-
#define __pud_free_tlb(tlb, x, addr) tlb_remove_ptdesc((tlb), virt_to_ptdesc(x))
#endif /* __PAGETABLE_PUD_FOLDED */
diff --git a/arch/mips/include/asm/pgalloc.h b/arch/mips/include/asm/pgalloc.h
index 2f123455e363..4346802e283f 100644
--- a/arch/mips/include/asm/pgalloc.h
+++ b/arch/mips/include/asm/pgalloc.h
@@ -13,7 +13,6 @@
#include <linux/mm.h>
#include <linux/sched.h>
-#define __HAVE_ARCH_PUD_ALLOC_ONE
#include <asm-generic/pgalloc.h>
static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
@@ -52,20 +51,6 @@ extern pgd_t *pgd_alloc(struct mm_struct *mm);
#ifndef __PAGETABLE_PUD_FOLDED
-static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
-{
- pud_t *pud;
- struct ptdesc *ptdesc = pagetable_alloc(GFP_KERNEL, PUD_TABLE_ORDER);
-
- if (!ptdesc)
- return NULL;
- pagetable_pud_ctor(ptdesc);
- pud = ptdesc_address(ptdesc);
-
- pud_init(pud);
- return pud;
-}
-
static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4d, pud_t *pud)
{
set_p4d(p4d, __p4d((unsigned long)pud));
diff --git a/include/asm-generic/pgalloc.h b/include/asm-generic/pgalloc.h
index 68e473908758..cc8445e6078d 100644
--- a/include/asm-generic/pgalloc.h
+++ b/include/asm-generic/pgalloc.h
@@ -182,24 +182,31 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
#if CONFIG_PGTABLE_LEVELS > 3
+#ifndef PUD_TABLE_ORDER
+#define PUD_TABLE_ORDER 0
+#endif
+
static inline pud_t *__pud_alloc_one_noprof(struct mm_struct *mm, unsigned long addr)
{
gfp_t gfp = GFP_PGTABLE_USER;
struct ptdesc *ptdesc;
+ pud_t *pud;
if (mm == &init_mm)
gfp = GFP_PGTABLE_KERNEL;
- ptdesc = pagetable_alloc_noprof(gfp, 0);
+ ptdesc = pagetable_alloc_noprof(gfp, PUD_TABLE_ORDER);
if (!ptdesc)
return NULL;
pagetable_pud_ctor(ptdesc);
+ pud = ptdesc_address(ptdesc);
+ pud_init(pud);
if (mm == &init_mm)
ptdesc_set_kernel(ptdesc);
- return ptdesc_address(ptdesc);
+ return pud;
}
#define __pud_alloc_one(...) alloc_hooks(__pud_alloc_one_noprof(__VA_ARGS__))
--
2.54.0