[PATCH v3 17/17] mm: pgtable: introduce generic pagetable_dtor_free()

From: Qi Zheng
Date: Mon Dec 23 2024 - 04:49:34 EST


The pte_free(), pmd_free(), __pud_free() and __p4d_free() in
asm-generic/pgalloc.h and the generic __tlb_remove_table() are basically
the same, so let's introduce pagetable_dtor_free() to deduplicate them.

In addition, the pagetable_dtor_free() in s390 actually does the same
thing, so let's s390 also calls generic pagetable_dtor_free().

Signed-off-by: Qi Zheng <zhengqi.arch@xxxxxxxxxxxxx>
Suggested-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx>
---
arch/s390/mm/pgalloc.c | 18 ++++++------------
include/asm-generic/pgalloc.h | 23 ++++-------------------
include/asm-generic/tlb.h | 5 +----
include/linux/mm.h | 8 ++++++++
4 files changed, 19 insertions(+), 35 deletions(-)

diff --git a/arch/s390/mm/pgalloc.c b/arch/s390/mm/pgalloc.c
index 3e002dea6278f..1e0727be48eaf 100644
--- a/arch/s390/mm/pgalloc.c
+++ b/arch/s390/mm/pgalloc.c
@@ -180,32 +180,26 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
return table;
}

-static void pagetable_dtor_free(struct ptdesc *ptdesc)
-{
- pagetable_dtor(ptdesc);
- pagetable_free(ptdesc);
-}
-
void page_table_free(struct mm_struct *mm, unsigned long *table)
{
- struct ptdesc *ptdesc = virt_to_ptdesc(table);
+ struct page *page = virt_to_page(table);

- pagetable_dtor_free(ptdesc);
+ pagetable_dtor_free(page);
}

#ifdef CONFIG_TRANSPARENT_HUGEPAGE
static void pte_free_now(struct rcu_head *head)
{
- struct ptdesc *ptdesc = container_of(head, struct ptdesc, pt_rcu_head);
+ struct page *page = container_of(head, struct page, rcu_head);

- pagetable_dtor_free(ptdesc);
+ pagetable_dtor_free(page);
}

void pte_free_defer(struct mm_struct *mm, pgtable_t pgtable)
{
- struct ptdesc *ptdesc = virt_to_ptdesc(pgtable);
+ struct page *page = virt_to_page(pgtable);

- call_rcu(&ptdesc->pt_rcu_head, pte_free_now);
+ call_rcu(&page->rcu_head, pte_free_now);
/*
* THPs are not allowed for KVM guests. Warn if pgste ever reaches here.
* Turn to the generic pte_free_defer() version once gmap is removed.
diff --git a/include/asm-generic/pgalloc.h b/include/asm-generic/pgalloc.h
index 4afb346eae255..7d327889df306 100644
--- a/include/asm-generic/pgalloc.h
+++ b/include/asm-generic/pgalloc.h
@@ -107,10 +107,7 @@ static inline pgtable_t pte_alloc_one_noprof(struct mm_struct *mm)
*/
static inline void pte_free(struct mm_struct *mm, struct page *pte_page)
{
- struct ptdesc *ptdesc = page_ptdesc(pte_page);
-
- pagetable_dtor(ptdesc);
- pagetable_free(ptdesc);
+ pagetable_dtor_free(pte_page);
}


@@ -150,11 +147,7 @@ static inline pmd_t *pmd_alloc_one_noprof(struct mm_struct *mm, unsigned long ad
#ifndef __HAVE_ARCH_PMD_FREE
static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
{
- struct ptdesc *ptdesc = virt_to_ptdesc(pmd);
-
- BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
- pagetable_dtor(ptdesc);
- pagetable_free(ptdesc);
+ pagetable_dtor_free(virt_to_page(pmd));
}
#endif

@@ -199,11 +192,7 @@ static inline pud_t *pud_alloc_one_noprof(struct mm_struct *mm, unsigned long ad

static inline void __pud_free(struct mm_struct *mm, pud_t *pud)
{
- struct ptdesc *ptdesc = virt_to_ptdesc(pud);
-
- BUG_ON((unsigned long)pud & (PAGE_SIZE-1));
- pagetable_dtor(ptdesc);
- pagetable_free(ptdesc);
+ pagetable_dtor_free(virt_to_page(pud));
}

#ifndef __HAVE_ARCH_PUD_FREE
@@ -245,11 +234,7 @@ static inline p4d_t *p4d_alloc_one_noprof(struct mm_struct *mm, unsigned long ad

static inline void __p4d_free(struct mm_struct *mm, p4d_t *p4d)
{
- struct ptdesc *ptdesc = virt_to_ptdesc(p4d);
-
- BUG_ON((unsigned long)p4d & (PAGE_SIZE-1));
- pagetable_dtor(ptdesc);
- pagetable_free(ptdesc);
+ pagetable_dtor_free(virt_to_page(p4d));
}

#ifndef __HAVE_ARCH_P4D_FREE
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
index 583e95568f52b..ef25169523602 100644
--- a/include/asm-generic/tlb.h
+++ b/include/asm-generic/tlb.h
@@ -211,10 +211,7 @@ struct mmu_table_batch {
#ifndef __HAVE_ARCH_TLB_REMOVE_TABLE
static inline void __tlb_remove_table(void *table)
{
- struct ptdesc *ptdesc = page_ptdesc((struct page *)table);
-
- pagetable_dtor(ptdesc);
- pagetable_free(ptdesc);
+ pagetable_dtor_free(table);
}
#endif

diff --git a/include/linux/mm.h b/include/linux/mm.h
index cad11fa10c192..cd078d51f47c7 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -3001,6 +3001,14 @@ static inline void pagetable_dtor(struct ptdesc *ptdesc)
lruvec_stat_sub_folio(folio, NR_PAGETABLE);
}

+static inline void pagetable_dtor_free(void *table)
+{
+ struct ptdesc *ptdesc = page_ptdesc((struct page *)table);
+
+ pagetable_dtor(ptdesc);
+ pagetable_free(ptdesc);
+}
+
static inline bool pagetable_pte_ctor(struct ptdesc *ptdesc)
{
struct folio *folio = ptdesc_folio(ptdesc);
--
2.20.1