Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] mm: Fix page-table teardown during memory hot-remove
@ 2026-10-08  7:30 Muchun Song
  2026-10-08  7:30 ` [PATCH 1/4] x86/mm: fix missing pgtable destructor for vmemmap tables Muchun Song
                   ` (4 more replies)
  0 siblings, 5 replies; 16+ messages in thread
From: Muchun Song @ 2026-10-08  7:30 UTC (permalink / raw)
  To: akpm
  Cc: linux-mm, stable, david, osalvador, dave.hansen, luto, peterz,
	tglx, mingo, bp, x86, hpa, catalin.marinas, will, mark.rutland,
	linux-arm-kernel, pjw, palmer, aou, alex, linux-riscv, agordeev,
	kevin.brodsky, bjorn, apopple, linux-kernel, muchun.song

Memory hot-remove can free page tables allocated through different
paths. Some of these paths run page-table constructors, while others,
including generic sparse-vmemmap population, do not. The teardown
paths on x86, RISC-V and arm64 do not consistently handle this
distinction, leaving constructors and destructors unbalanced and
corrupting NR_PAGETABLE accounting.

On x86, the destructor is missing for vmemmap PTE tables allocated by
HugeTLB vmemmap optimization. RISC-V also misses the destructor for
constructed PUD tables. Conversely, arm64 and RISC-V can run
destructors on vmemmap tables that were never constructed.

This series uses PageTable() to determine whether a destructor is
needed before freeing a page-table page. The RISC-V fixes share a
common freeing helper across PTE, PMD and PUD teardown.

This series is limited to bug fixes for the existing teardown paths.
A follow-up series will convert runtime vmemmap page-table allocation
to the generic page-table allocation helpers, ensuring that these
tables run the corresponding constructors. Once these tables follow
the normal constructor and destructor lifecycle, the PageTable()
checks in the arm64 and RISC-V teardown paths can be removed.

Muchun Song (4):
  x86/mm: fix missing pgtable destructor for vmemmap tables
  riscv/mm: fix hotplug page-table destructor handling
  riscv/mm: fix missing destructor for hotplug PUD tables
  arm64/mm: fix destructor for unconstructed hotplug page tables

 arch/arm64/mm/mmu.c   |  3 ++-
 arch/riscv/mm/init.c  | 34 +++++++++++++++-------------------
 arch/x86/mm/init_64.c |  2 ++
 3 files changed, 19 insertions(+), 20 deletions(-)


base-commit: a92f009ac1c21986ff1ea0706419e545a4739513
-- 
2.54.0



^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 1/4] x86/mm: fix missing pgtable destructor for vmemmap tables
  2026-10-08  7:30 [PATCH 0/4] mm: Fix page-table teardown during memory hot-remove Muchun Song
@ 2026-10-08  7:30 ` Muchun Song
  2026-10-08  8:32   ` Muchun Song
                     ` (2 more replies)
  2026-10-08  7:30 ` [PATCH 2/4] riscv/mm: fix hotplug page-table destructor handling Muchun Song
                   ` (3 subsequent siblings)
  4 siblings, 3 replies; 16+ messages in thread
From: Muchun Song @ 2026-10-08  7:30 UTC (permalink / raw)
  To: akpm
  Cc: linux-mm, stable, david, osalvador, dave.hansen, luto, peterz,
	tglx, mingo, bp, x86, hpa, catalin.marinas, will, mark.rutland,
	linux-arm-kernel, pjw, palmer, aou, alex, linux-riscv, agordeev,
	kevin.brodsky, bjorn, apopple, linux-kernel, muchun.song

Since commit 49f599666420 ("mm: call ctor/dtor for kernel PTEs"),
pte_alloc_one_kernel() runs the page-table constructor for kernel PTE
tables.

HugeTLB vmemmap optimization uses pte_alloc_one_kernel() when splitting
a PMD. Restoring the vmemmap backing pages does not collapse the PTE
table, so a later memory hot-remove eventually frees that table through
free_pagetable(). That path currently calls pagetable_free() directly
without decrementing NR_PAGETABLE.

Use PageTable() to identify constructor-backed tables and run the
matching destructor before freeing them. Keep reserved and
constructor-free tables on their existing paths. This also prepares
vmemmap teardown for generic runtime allocations through the normal
pgalloc helpers.

Fixes: 49f599666420 ("mm: call ctor/dtor for kernel PTEs")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Muchun Song <songmuchun@bytedance.com>
---
 arch/x86/mm/init_64.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 70e682180291..a3ea627157ab 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -1003,6 +1003,8 @@ static void __meminit free_pagetable(struct page *page)
 {
 	if (PageReserved(page))
 		free_reserved_page(page);
+	else if (PageTable(page))
+		pagetable_dtor_free(page_ptdesc(page));
 	else
 		pagetable_free(page_ptdesc(page));
 }
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 2/4] riscv/mm: fix hotplug page-table destructor handling
  2026-10-08  7:30 [PATCH 0/4] mm: Fix page-table teardown during memory hot-remove Muchun Song
  2026-10-08  7:30 ` [PATCH 1/4] x86/mm: fix missing pgtable destructor for vmemmap tables Muchun Song
@ 2026-10-08  7:30 ` Muchun Song
  2026-10-09  6:09   ` Björn Töpel
  2026-10-09 20:37   ` David Hildenbrand (Arm)
  2026-10-08  7:30 ` [PATCH 3/4] riscv/mm: fix missing destructor for hotplug PUD tables Muchun Song
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 16+ messages in thread
From: Muchun Song @ 2026-10-08  7:30 UTC (permalink / raw)
  To: akpm
  Cc: linux-mm, stable, david, osalvador, dave.hansen, luto, peterz,
	tglx, mingo, bp, x86, hpa, catalin.marinas, will, mark.rutland,
	linux-arm-kernel, pjw, palmer, aou, alex, linux-riscv, agordeev,
	kevin.brodsky, bjorn, apopple, linux-kernel, muchun.song

RISC-V uses the same memory-hotplug teardown code for the linear map and
vmemmap, although their page-table pages are not always allocated in the
same way. Late linear-map allocations run page-table constructors, while
vmemmap and early allocations may provide constructor-free pages.

The PTE path unconditionally runs the destructor, which is wrong for
constructor-free vmemmap tables. The PMD path avoids that problem by
using is_vmemmap as a proxy for constructor state, but that assumption
will no longer hold once runtime vmemmap allocations use the normal
pgalloc helpers.

Page-table constructors record their state in PG_table. Centralize
page-table freeing and use PageTable() to decide whether the destructor
is required. Keep reserved and constructor-free pages on their existing
freeing paths.

Fixes: c75a74f4ba19 ("riscv: mm: Add memory hotplugging support")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Muchun Song <songmuchun@bytedance.com>
---
 arch/riscv/mm/init.c | 29 ++++++++++++++---------------
 1 file changed, 14 insertions(+), 15 deletions(-)

diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 857f9a55039c..429a0b015ec1 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -1486,10 +1486,19 @@ struct execmem_info __init *execmem_arch_setup(void)
 #endif /* CONFIG_EXECMEM */
 
 #ifdef CONFIG_MEMORY_HOTPLUG
+static void __meminit free_pagetable(struct page *page)
+{
+	if (PageReserved(page))
+		free_reserved_page(page);
+	else if (PageTable(page))
+		pagetable_dtor_free(page_ptdesc(page));
+	else
+		pagetable_free(page_ptdesc(page));
+}
+
 static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd)
 {
 	struct page *page = pmd_page(*pmd);
-	struct ptdesc *ptdesc = page_ptdesc(page);
 	pte_t *pte;
 	int i;
 
@@ -1499,18 +1508,13 @@ static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd)
 			return;
 	}
 
-	pagetable_dtor(ptdesc);
-	if (PageReserved(page))
-		free_reserved_page(page);
-	else
-		pagetable_free(ptdesc);
+	free_pagetable(page);
 	pmd_clear(pmd);
 }
 
-static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud, bool is_vmemmap)
+static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud)
 {
 	struct page *page = pud_page(*pud);
-	struct ptdesc *ptdesc = page_ptdesc(page);
 	pmd_t *pmd;
 	int i;
 
@@ -1520,12 +1524,7 @@ static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud, bool is_vmemm
 			return;
 	}
 
-	if (!is_vmemmap)
-		pagetable_dtor(ptdesc);
-	if (PageReserved(page))
-		free_reserved_page(page);
-	else
-		pagetable_free(ptdesc);
+	free_pagetable(page);
 	pud_clear(pud);
 }
 
@@ -1645,7 +1644,7 @@ static void __meminit remove_pud_mapping(pud_t *pud_base, unsigned long addr, un
 		remove_pmd_mapping(pmd_base, addr, next, is_vmemmap, altmap);
 
 		if (pgtable_l4_enabled)
-			free_pmd_table(pmd_base, pudp, is_vmemmap);
+			free_pmd_table(pmd_base, pudp);
 	}
 }
 
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 3/4] riscv/mm: fix missing destructor for hotplug PUD tables
  2026-10-08  7:30 [PATCH 0/4] mm: Fix page-table teardown during memory hot-remove Muchun Song
  2026-10-08  7:30 ` [PATCH 1/4] x86/mm: fix missing pgtable destructor for vmemmap tables Muchun Song
  2026-10-08  7:30 ` [PATCH 2/4] riscv/mm: fix hotplug page-table destructor handling Muchun Song
@ 2026-10-08  7:30 ` Muchun Song
  2026-10-09 20:38   ` David Hildenbrand (Arm)
  2026-10-08  7:30 ` [PATCH 4/4] arm64/mm: fix destructor for unconstructed hotplug page tables Muchun Song
  2026-10-09 20:48 ` [PATCH 0/4] mm: Fix page-table teardown during memory hot-remove Dave Hansen
  4 siblings, 1 reply; 16+ messages in thread
From: Muchun Song @ 2026-10-08  7:30 UTC (permalink / raw)
  To: akpm
  Cc: linux-mm, stable, david, osalvador, dave.hansen, luto, peterz,
	tglx, mingo, bp, x86, hpa, catalin.marinas, will, mark.rutland,
	linux-arm-kernel, pjw, palmer, aou, alex, linux-riscv, agordeev,
	kevin.brodsky, bjorn, apopple, linux-kernel, muchun.song

Commit 8472cc4503eb ("riscv: mm: call PUD/P4D ctor in special kernel
pgtable alloc") made alloc_pud_late() run the PUD page-table constructor.
However, free_pud_table() still frees non-reserved PUD tables directly
without decrementing NR_PAGETABLE.

Free PUD tables through the common free_pagetable() helper so that
constructor-backed tables run the matching destructor before being
freed.

Fixes: 8472cc4503eb ("riscv: mm: call PUD/P4D ctor in special kernel pgtable alloc")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Muchun Song <songmuchun@bytedance.com>
---
 arch/riscv/mm/init.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 429a0b015ec1..62077539ee78 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -1540,10 +1540,7 @@ static void __meminit free_pud_table(pud_t *pud_start, p4d_t *p4d)
 			return;
 	}
 
-	if (PageReserved(page))
-		free_reserved_page(page);
-	else
-		__free_pages(page, 0);
+	free_pagetable(page);
 	p4d_clear(p4d);
 }
 
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 4/4] arm64/mm: fix destructor for unconstructed hotplug page tables
  2026-10-08  7:30 [PATCH 0/4] mm: Fix page-table teardown during memory hot-remove Muchun Song
                   ` (2 preceding siblings ...)
  2026-10-08  7:30 ` [PATCH 3/4] riscv/mm: fix missing destructor for hotplug PUD tables Muchun Song
@ 2026-10-08  7:30 ` Muchun Song
  2026-10-09 20:43   ` David Hildenbrand (Arm)
  2026-10-09 20:48 ` [PATCH 0/4] mm: Fix page-table teardown during memory hot-remove Dave Hansen
  4 siblings, 1 reply; 16+ messages in thread
From: Muchun Song @ 2026-10-08  7:30 UTC (permalink / raw)
  To: akpm
  Cc: linux-mm, stable, david, osalvador, dave.hansen, luto, peterz,
	tglx, mingo, bp, x86, hpa, catalin.marinas, will, mark.rutland,
	linux-arm-kernel, pjw, palmer, aou, alex, linux-riscv, agordeev,
	kevin.brodsky, bjorn, apopple, linux-kernel, muchun.song

Commit c594b83457cc ("arm64: mm: call pagetable dtor when freeing
hot-removed page tables") made free_hotplug_pgtable_page()
unconditionally run the page-table destructor. This matches page tables
allocated by the arm64 mapping code, which runs the corresponding
constructors.

However, arm64 also uses the generic sparse-vmemmap population code.
Runtime intermediate page tables allocated by that code do not run a
page-table constructor. Freeing one during memory hot-remove therefore
runs a destructor without a matching constructor and corrupts
NR_PAGETABLE accounting.

Use PageTable() to run the destructor only for page-table pages whose
constructor initialized them. This keeps the arm64-created page-table
lifecycle balanced while safely freeing constructor-free vmemmap tables.

Fixes: c594b83457cc ("arm64: mm: call pagetable dtor when freeing hot-removed page tables")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Muchun Song <songmuchun@bytedance.com>
---
 arch/arm64/mm/mmu.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 7343ac9294f8..688b33095651 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -1495,7 +1495,8 @@ static void free_hotplug_page_range(struct page *page, size_t size,
 
 static void free_hotplug_pgtable_page(struct page *page)
 {
-	pagetable_dtor(page_ptdesc(page));
+	if (PageTable(page))
+		pagetable_dtor(page_ptdesc(page));
 	free_hotplug_page_range(page, PAGE_SIZE, NULL);
 }
 
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/4] x86/mm: fix missing pgtable destructor for vmemmap tables
  2026-10-08  7:30 ` [PATCH 1/4] x86/mm: fix missing pgtable destructor for vmemmap tables Muchun Song
@ 2026-10-08  8:32   ` Muchun Song
  2026-10-09 20:29     ` David Hildenbrand (Arm)
  2026-10-09 20:33   ` David Hildenbrand (Arm)
  2026-10-09 20:54   ` Dave Hansen
  2 siblings, 1 reply; 16+ messages in thread
From: Muchun Song @ 2026-10-08  8:32 UTC (permalink / raw)
  To: Muchun Song
  Cc: akpm, linux-mm, stable, david, osalvador, dave.hansen, luto,
	peterz, tglx, mingo, bp, x86, hpa, catalin.marinas, will,
	mark.rutland, linux-arm-kernel, pjw, palmer, aou, alex,
	linux-riscv, agordeev, kevin.brodsky, bjorn, apopple,
	linux-kernel



> On Oct 8, 2026, at 09:30, Muchun Song <songmuchun@bytedance.com> wrote:
> 
> Since commit 49f599666420 ("mm: call ctor/dtor for kernel PTEs"),
> pte_alloc_one_kernel() runs the page-table constructor for kernel PTE
> tables.
> 
> HugeTLB vmemmap optimization uses pte_alloc_one_kernel() when splitting
> a PMD. Restoring the vmemmap backing pages does not collapse the PTE
> table, so a later memory hot-remove eventually frees that table through
> free_pagetable(). That path currently calls pagetable_free() directly
> without decrementing NR_PAGETABLE.
> 
> Use PageTable() to identify constructor-backed tables and run the
> matching destructor before freeing them. Keep reserved and
> constructor-free tables on their existing paths. This also prepares
> vmemmap teardown for generic runtime allocations through the normal
> pgalloc helpers.
> 
> Fixes: 49f599666420 ("mm: call ctor/dtor for kernel PTEs")
> Cc: stable@vger.kernel.org
> Assisted-by: LLM
> Signed-off-by: Muchun Song <songmuchun@bytedance.com>
> ---
> arch/x86/mm/init_64.c | 2 ++
> 1 file changed, 2 insertions(+)
> 
> diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
> index 70e682180291..a3ea627157ab 100644
> --- a/arch/x86/mm/init_64.c
> +++ b/arch/x86/mm/init_64.c
> @@ -1003,6 +1003,8 @@ static void __meminit free_pagetable(struct page *page)
> {
> 	if (PageReserved(page))
> 		free_reserved_page(page);
> + 	else if (PageTable(page))
> + 		pagetable_dtor_free(page_ptdesc(page));

Sashiko mentioned that kernel page table pages and vmemmap pages are
freed to the buddy allocator before their parent entries are cleared
and before the TLB is flushed, creating a dangling pointer window.

That's a a real but pre-existing issue, I will not fix that in this
series.

> 	else
> 		pagetable_free(page_ptdesc(page));
> }
> -- 
> 2.54.0
> 



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/4] riscv/mm: fix hotplug page-table destructor handling
  2026-10-08  7:30 ` [PATCH 2/4] riscv/mm: fix hotplug page-table destructor handling Muchun Song
@ 2026-10-09  6:09   ` Björn Töpel
  2026-10-09 14:14     ` Muchun Song
  2026-10-09 20:37   ` David Hildenbrand (Arm)
  1 sibling, 1 reply; 16+ messages in thread
From: Björn Töpel @ 2026-10-09  6:09 UTC (permalink / raw)
  To: Muchun Song, akpm
  Cc: linux-mm, stable, david, osalvador, dave.hansen, luto, peterz,
	tglx, mingo, bp, x86, hpa, catalin.marinas, will, mark.rutland,
	linux-arm-kernel, pjw, palmer, aou, alex, linux-riscv, agordeev,
	kevin.brodsky, bjorn, apopple, linux-kernel, muchun.song

Muchun Song <songmuchun@bytedance.com> writes:

> RISC-V uses the same memory-hotplug teardown code for the linear map and
> vmemmap, although their page-table pages are not always allocated in the
> same way. Late linear-map allocations run page-table constructors, while
> vmemmap and early allocations may provide constructor-free pages.
>
> The PTE path unconditionally runs the destructor, which is wrong for
> constructor-free vmemmap tables. The PMD path avoids that problem by
> using is_vmemmap as a proxy for constructor state, but that assumption
> will no longer hold once runtime vmemmap allocations use the normal
> pgalloc helpers.
>
> Page-table constructors record their state in PG_table. Centralize
> page-table freeing and use PageTable() to decide whether the destructor
> is required. Keep reserved and constructor-free pages on their existing
> freeing paths.
>
> Fixes: c75a74f4ba19 ("riscv: mm: Add memory hotplugging support")
> Cc: stable@vger.kernel.org
> Assisted-by: LLM
> Signed-off-by: Muchun Song <songmuchun@bytedance.com>
> ---
>  arch/riscv/mm/init.c | 29 ++++++++++++++---------------
>  1 file changed, 14 insertions(+), 15 deletions(-)
>
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index 857f9a55039c..429a0b015ec1 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -1486,10 +1486,19 @@ struct execmem_info __init *execmem_arch_setup(void)
>  #endif /* CONFIG_EXECMEM */
>  
>  #ifdef CONFIG_MEMORY_HOTPLUG
> +static void __meminit free_pagetable(struct page *page)
> +{
> +	if (PageReserved(page))
> +		free_reserved_page(page);
> +	else if (PageTable(page))
> +		pagetable_dtor_free(page_ptdesc(page));
> +	else
> +		pagetable_free(page_ptdesc(page));
> +}

Is PageReserved() enought to determine if there's no dtor to run? On
rv64 your code is correct, but maybe for robustness?

  | if (PageTable(page))
  |         pagetable_dtor(page_ptdesc(page));
  | 
  | if (PageReserved(page))
  |         free_reserved_page(page);
  | else
  |         pagetable_free(page_ptdesc(page));


Björn


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/4] riscv/mm: fix hotplug page-table destructor handling
  2026-10-09  6:09   ` Björn Töpel
@ 2026-10-09 14:14     ` Muchun Song
  0 siblings, 0 replies; 16+ messages in thread
From: Muchun Song @ 2026-10-09 14:14 UTC (permalink / raw)
  To: Björn Töpel
  Cc: Muchun Song, akpm, linux-mm, stable, david, osalvador,
	dave.hansen, luto, peterz, tglx, mingo, bp, x86, hpa,
	catalin.marinas, will, mark.rutland, linux-arm-kernel, pjw,
	palmer, aou, alex, linux-riscv, agordeev, kevin.brodsky, bjorn,
	apopple, linux-kernel



> On Oct 9, 2026, at 14:09, Björn Töpel <bjorn@kernel.org> wrote:
> 
> Muchun Song <songmuchun@bytedance.com> writes:
> 
>> RISC-V uses the same memory-hotplug teardown code for the linear map and
>> vmemmap, although their page-table pages are not always allocated in the
>> same way. Late linear-map allocations run page-table constructors, while
>> vmemmap and early allocations may provide constructor-free pages.
>> 
>> The PTE path unconditionally runs the destructor, which is wrong for
>> constructor-free vmemmap tables. The PMD path avoids that problem by
>> using is_vmemmap as a proxy for constructor state, but that assumption
>> will no longer hold once runtime vmemmap allocations use the normal
>> pgalloc helpers.
>> 
>> Page-table constructors record their state in PG_table. Centralize
>> page-table freeing and use PageTable() to decide whether the destructor
>> is required. Keep reserved and constructor-free pages on their existing
>> freeing paths.
>> 
>> Fixes: c75a74f4ba19 ("riscv: mm: Add memory hotplugging support")
>> Cc: stable@vger.kernel.org
>> Assisted-by: LLM
>> Signed-off-by: Muchun Song <songmuchun@bytedance.com>
>> ---
>> arch/riscv/mm/init.c | 29 ++++++++++++++---------------
>> 1 file changed, 14 insertions(+), 15 deletions(-)
>> 
>> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
>> index 857f9a55039c..429a0b015ec1 100644
>> --- a/arch/riscv/mm/init.c
>> +++ b/arch/riscv/mm/init.c
>> @@ -1486,10 +1486,19 @@ struct execmem_info __init *execmem_arch_setup(void)
>> #endif /* CONFIG_EXECMEM */
>> 
>> #ifdef CONFIG_MEMORY_HOTPLUG
>> +static void __meminit free_pagetable(struct page *page)
>> +{
>> + 	if (PageReserved(page))
>> + 		free_reserved_page(page);
>> + 	else if (PageTable(page))
>> + 		pagetable_dtor_free(page_ptdesc(page));
>> + 	else
>> + 		pagetable_free(page_ptdesc(page));
>> +}
> 
> Is PageReserved() enought to determine if there's no dtor to run? On

Yes.

> rv64 your code is correct, but maybe for robustness?
> 
>  | if (PageTable(page))
>  |         pagetable_dtor(page_ptdesc(page));
>  | 
>  | if (PageReserved(page))
>  |         free_reserved_page(page);
>  | else
>  |         pagetable_free(page_ptdesc(page));

his looks good to me as well. I'll change it in the next version. Thanks!

Muchun

> 
> 
> Björn



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/4] x86/mm: fix missing pgtable destructor for vmemmap tables
  2026-10-08  8:32   ` Muchun Song
@ 2026-10-09 20:29     ` David Hildenbrand (Arm)
  0 siblings, 0 replies; 16+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-09 20:29 UTC (permalink / raw)
  To: Muchun Song, Muchun Song
  Cc: akpm, linux-mm, stable, osalvador, dave.hansen, luto, peterz,
	tglx, mingo, bp, x86, hpa, catalin.marinas, will, mark.rutland,
	linux-arm-kernel, pjw, palmer, aou, alex, linux-riscv, agordeev,
	kevin.brodsky, bjorn, apopple, linux-kernel

On 10/8/26 10:32, Muchun Song wrote:
> 
> 
>> On Oct 8, 2026, at 09:30, Muchun Song <songmuchun@bytedance.com> wrote:
>>
>> Since commit 49f599666420 ("mm: call ctor/dtor for kernel PTEs"),
>> pte_alloc_one_kernel() runs the page-table constructor for kernel PTE
>> tables.
>>
>> HugeTLB vmemmap optimization uses pte_alloc_one_kernel() when splitting
>> a PMD. Restoring the vmemmap backing pages does not collapse the PTE
>> table, so a later memory hot-remove eventually frees that table through
>> free_pagetable(). That path currently calls pagetable_free() directly
>> without decrementing NR_PAGETABLE.
>>
>> Use PageTable() to identify constructor-backed tables and run the
>> matching destructor before freeing them. Keep reserved and
>> constructor-free tables on their existing paths. This also prepares
>> vmemmap teardown for generic runtime allocations through the normal
>> pgalloc helpers.
>>
>> Fixes: 49f599666420 ("mm: call ctor/dtor for kernel PTEs")
>> Cc: stable@vger.kernel.org
>> Assisted-by: LLM
>> Signed-off-by: Muchun Song <songmuchun@bytedance.com>
>> ---
>> arch/x86/mm/init_64.c | 2 ++
>> 1 file changed, 2 insertions(+)
>>
>> diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
>> index 70e682180291..a3ea627157ab 100644
>> --- a/arch/x86/mm/init_64.c
>> +++ b/arch/x86/mm/init_64.c
>> @@ -1003,6 +1003,8 @@ static void __meminit free_pagetable(struct page *page)
>> {
>> 	if (PageReserved(page))
>> 		free_reserved_page(page);
>> + 	else if (PageTable(page))
>> + 		pagetable_dtor_free(page_ptdesc(page));
> 
> Sashiko mentioned that kernel page table pages and vmemmap pages are
> freed to the buddy allocator before their parent entries are cleared
> and before the TLB is flushed, creating a dangling pointer window.
> 
> That's a a real but pre-existing issue, I will not fix that in this
> series.

Memory is getting removed, concurrent access to directmap+vmemmap is not
expected unless BUG I think. That should make this less critical I think ...
(except speculation? not sure if that applies)

-- 
Cheers,

David


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/4] x86/mm: fix missing pgtable destructor for vmemmap tables
  2026-10-08  7:30 ` [PATCH 1/4] x86/mm: fix missing pgtable destructor for vmemmap tables Muchun Song
  2026-10-08  8:32   ` Muchun Song
@ 2026-10-09 20:33   ` David Hildenbrand (Arm)
  2026-10-09 20:36     ` David Hildenbrand (Arm)
  2026-10-09 20:54   ` Dave Hansen
  2 siblings, 1 reply; 16+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-09 20:33 UTC (permalink / raw)
  To: Muchun Song, akpm
  Cc: linux-mm, stable, osalvador, dave.hansen, luto, peterz, tglx,
	mingo, bp, x86, hpa, catalin.marinas, will, mark.rutland,
	linux-arm-kernel, pjw, palmer, aou, alex, linux-riscv, agordeev,
	kevin.brodsky, bjorn, apopple, linux-kernel, muchun.song

On 10/8/26 09:30, Muchun Song wrote:
> Since commit 49f599666420 ("mm: call ctor/dtor for kernel PTEs"),
> pte_alloc_one_kernel() runs the page-table constructor for kernel PTE
> tables.
> 
> HugeTLB vmemmap optimization uses pte_alloc_one_kernel() when splitting
> a PMD. Restoring the vmemmap backing pages does not collapse the PTE
> table, so a later memory hot-remove eventually frees that table through
> free_pagetable(). That path currently calls pagetable_free() directly
> without decrementing NR_PAGETABLE.
> 
> Use PageTable() to identify constructor-backed tables and run the
> matching destructor before freeing them. Keep reserved and
> constructor-free tables on their existing paths. This also prepares
> vmemmap teardown for generic runtime allocations through the normal
> pgalloc helpers.
> 
> Fixes: 49f599666420 ("mm: call ctor/dtor for kernel PTEs")
> Cc: stable@vger.kernel.org
> Assisted-by: LLM
> Signed-off-by: Muchun Song <songmuchun@bytedance.com>
> ---
>  arch/x86/mm/init_64.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
> index 70e682180291..a3ea627157ab 100644
> --- a/arch/x86/mm/init_64.c
> +++ b/arch/x86/mm/init_64.c
> @@ -1003,6 +1003,8 @@ static void __meminit free_pagetable(struct page *page)
>  {
>  	if (PageReserved(page))
>  		free_reserved_page(page);
> +	else if (PageTable(page))
> +		pagetable_dtor_free(page_ptdesc(page));
>  	else
>  		pagetable_free(page_ptdesc(page));
>  }

pagetable_free() will do ptdesc_test_kernel(pt) -> pagetable_free_kernel(pt) ->
pagetable_dtor_free().


IIUC, pte_alloc_one_kernel() will set ptdesc_set_kernel(ptdesc);

-- 
Cheers,

David


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/4] x86/mm: fix missing pgtable destructor for vmemmap tables
  2026-10-09 20:33   ` David Hildenbrand (Arm)
@ 2026-10-09 20:36     ` David Hildenbrand (Arm)
  0 siblings, 0 replies; 16+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-09 20:36 UTC (permalink / raw)
  To: Muchun Song, akpm
  Cc: linux-mm, stable, osalvador, dave.hansen, luto, peterz, tglx,
	mingo, bp, x86, hpa, catalin.marinas, will, mark.rutland,
	linux-arm-kernel, pjw, palmer, aou, alex, linux-riscv, agordeev,
	kevin.brodsky, bjorn, apopple, linux-kernel, muchun.song

On 10/9/26 22:33, David Hildenbrand (Arm) wrote:
> On 10/8/26 09:30, Muchun Song wrote:
>> Since commit 49f599666420 ("mm: call ctor/dtor for kernel PTEs"),
>> pte_alloc_one_kernel() runs the page-table constructor for kernel PTE
>> tables.
>>
>> HugeTLB vmemmap optimization uses pte_alloc_one_kernel() when splitting
>> a PMD. Restoring the vmemmap backing pages does not collapse the PTE
>> table, so a later memory hot-remove eventually frees that table through
>> free_pagetable(). That path currently calls pagetable_free() directly
>> without decrementing NR_PAGETABLE.
>>
>> Use PageTable() to identify constructor-backed tables and run the
>> matching destructor before freeing them. Keep reserved and
>> constructor-free tables on their existing paths. This also prepares
>> vmemmap teardown for generic runtime allocations through the normal
>> pgalloc helpers.
>>
>> Fixes: 49f599666420 ("mm: call ctor/dtor for kernel PTEs")
>> Cc: stable@vger.kernel.org
>> Assisted-by: LLM
>> Signed-off-by: Muchun Song <songmuchun@bytedance.com>
>> ---
>>  arch/x86/mm/init_64.c | 2 ++
>>  1 file changed, 2 insertions(+)
>>
>> diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
>> index 70e682180291..a3ea627157ab 100644
>> --- a/arch/x86/mm/init_64.c
>> +++ b/arch/x86/mm/init_64.c
>> @@ -1003,6 +1003,8 @@ static void __meminit free_pagetable(struct page *page)
>>  {
>>  	if (PageReserved(page))
>>  		free_reserved_page(page);
>> +	else if (PageTable(page))
>> +		pagetable_dtor_free(page_ptdesc(page));
>>  	else
>>  		pagetable_free(page_ptdesc(page));
>>  }
> 
> pagetable_free() will do ptdesc_test_kernel(pt) -> pagetable_free_kernel(pt) ->
> pagetable_dtor_free().

Ah, behavior depends on CONFIG_ASYNC_KERNEL_PGTABLE_FREE$ ...

Why not do the right thing in pagetable_free() instead?

-- 
Cheers,

David


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/4] riscv/mm: fix hotplug page-table destructor handling
  2026-10-08  7:30 ` [PATCH 2/4] riscv/mm: fix hotplug page-table destructor handling Muchun Song
  2026-10-09  6:09   ` Björn Töpel
@ 2026-10-09 20:37   ` David Hildenbrand (Arm)
  1 sibling, 0 replies; 16+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-09 20:37 UTC (permalink / raw)
  To: Muchun Song, akpm
  Cc: linux-mm, stable, osalvador, dave.hansen, luto, peterz, tglx,
	mingo, bp, x86, hpa, catalin.marinas, will, mark.rutland,
	linux-arm-kernel, pjw, palmer, aou, alex, linux-riscv, agordeev,
	kevin.brodsky, bjorn, apopple, linux-kernel, muchun.song

On 10/8/26 09:30, Muchun Song wrote:
> RISC-V uses the same memory-hotplug teardown code for the linear map and
> vmemmap, although their page-table pages are not always allocated in the
> same way. Late linear-map allocations run page-table constructors, while
> vmemmap and early allocations may provide constructor-free pages.
> 
> The PTE path unconditionally runs the destructor, which is wrong for
> constructor-free vmemmap tables. The PMD path avoids that problem by
> using is_vmemmap as a proxy for constructor state, but that assumption
> will no longer hold once runtime vmemmap allocations use the normal
> pgalloc helpers.
> 
> Page-table constructors record their state in PG_table. Centralize
> page-table freeing and use PageTable() to decide whether the destructor
> is required. Keep reserved and constructor-free pages on their existing
> freeing paths.
> 
> Fixes: c75a74f4ba19 ("riscv: mm: Add memory hotplugging support")
> Cc: stable@vger.kernel.org
> Assisted-by: LLM
> Signed-off-by: Muchun Song <songmuchun@bytedance.com>
> ---
>  arch/riscv/mm/init.c | 29 ++++++++++++++---------------
>  1 file changed, 14 insertions(+), 15 deletions(-)
> 
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index 857f9a55039c..429a0b015ec1 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -1486,10 +1486,19 @@ struct execmem_info __init *execmem_arch_setup(void)
>  #endif /* CONFIG_EXECMEM */
>  
>  #ifdef CONFIG_MEMORY_HOTPLUG
> +static void __meminit free_pagetable(struct page *page)
> +{
> +	if (PageReserved(page))
> +		free_reserved_page(page);
> +	else if (PageTable(page))
> +		pagetable_dtor_free(page_ptdesc(page));
> +	else
> +		pagetable_free(page_ptdesc(page));

Similar thought, can't we detect that in pagetable_free() somehow and avoid
requiring callers to handle that?

-- 
Cheers,

David


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/4] riscv/mm: fix missing destructor for hotplug PUD tables
  2026-10-08  7:30 ` [PATCH 3/4] riscv/mm: fix missing destructor for hotplug PUD tables Muchun Song
@ 2026-10-09 20:38   ` David Hildenbrand (Arm)
  0 siblings, 0 replies; 16+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-09 20:38 UTC (permalink / raw)
  To: Muchun Song, akpm
  Cc: linux-mm, stable, osalvador, dave.hansen, luto, peterz, tglx,
	mingo, bp, x86, hpa, catalin.marinas, will, mark.rutland,
	linux-arm-kernel, pjw, palmer, aou, alex, linux-riscv, agordeev,
	kevin.brodsky, bjorn, apopple, linux-kernel, muchun.song

On 10/8/26 09:30, Muchun Song wrote:
> Commit 8472cc4503eb ("riscv: mm: call PUD/P4D ctor in special kernel
> pgtable alloc") made alloc_pud_late() run the PUD page-table constructor.
> However, free_pud_table() still frees non-reserved PUD tables directly
> without decrementing NR_PAGETABLE.
> 
> Free PUD tables through the common free_pagetable() helper so that
> constructor-backed tables run the matching destructor before being
> freed.
> 
> Fixes: 8472cc4503eb ("riscv: mm: call PUD/P4D ctor in special kernel pgtable alloc")
> Cc: stable@vger.kernel.org
> Assisted-by: LLM
> Signed-off-by: Muchun Song <songmuchun@bytedance.com>
> ---
>  arch/riscv/mm/init.c | 5 +----
>  1 file changed, 1 insertion(+), 4 deletions(-)
> 
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index 429a0b015ec1..62077539ee78 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -1540,10 +1540,7 @@ static void __meminit free_pud_table(pud_t *pud_start, p4d_t *p4d)
>  			return;
>  	}
>  
> -	if (PageReserved(page))
> -		free_reserved_page(page);
> -	else
> -		__free_pages(page, 0);
> +	free_pagetable(page);
>  	p4d_clear(p4d);
>  }
>  

Routing this through a single helper looks correct.

Acked-by: David Hildenbrand (Arm) <david@kernel.org>

-- 
Cheers,

David


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 4/4] arm64/mm: fix destructor for unconstructed hotplug page tables
  2026-10-08  7:30 ` [PATCH 4/4] arm64/mm: fix destructor for unconstructed hotplug page tables Muchun Song
@ 2026-10-09 20:43   ` David Hildenbrand (Arm)
  0 siblings, 0 replies; 16+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-09 20:43 UTC (permalink / raw)
  To: Muchun Song, akpm
  Cc: linux-mm, stable, osalvador, dave.hansen, luto, peterz, tglx,
	mingo, bp, x86, hpa, catalin.marinas, will, mark.rutland,
	linux-arm-kernel, pjw, palmer, aou, alex, linux-riscv, agordeev,
	kevin.brodsky, bjorn, apopple, linux-kernel, muchun.song

On 10/8/26 09:30, Muchun Song wrote:
> Commit c594b83457cc ("arm64: mm: call pagetable dtor when freeing
> hot-removed page tables") made free_hotplug_pgtable_page()
> unconditionally run the page-table destructor. This matches page tables
> allocated by the arm64 mapping code, which runs the corresponding
> constructors.
> 
> However, arm64 also uses the generic sparse-vmemmap population code.
> Runtime intermediate page tables allocated by that code do not run a
> page-table constructor.

Why do we have that inconsistency? It seems to cause pain :)

> Freeing one during memory hot-remove therefore
> runs a destructor without a matching constructor and corrupts
> NR_PAGETABLE accounting.
> 
> Use PageTable() to run the destructor only for page-table pages whose
> constructor initialized them. This keeps the arm64-created page-table
> lifecycle balanced while safely freeing constructor-free vmemmap tables.
> 
> Fixes: c594b83457cc ("arm64: mm: call pagetable dtor when freeing hot-removed page tables")
> Cc: stable@vger.kernel.org
> Assisted-by: LLM
> Signed-off-by: Muchun Song <songmuchun@bytedance.com>
> ---
>  arch/arm64/mm/mmu.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 7343ac9294f8..688b33095651 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -1495,7 +1495,8 @@ static void free_hotplug_page_range(struct page *page, size_t size,
>  
>  static void free_hotplug_pgtable_page(struct page *page)
>  {
> -	pagetable_dtor(page_ptdesc(page));
> +	if (PageTable(page))
> +		pagetable_dtor(page_ptdesc(page));
>  	free_hotplug_page_range(page, PAGE_SIZE, NULL);

That results in a __free_pages() for  ones allocated by sparse-vmemmap
population code. Are we sure that's the right thing to do?

This is all so inconsistent and confusing :(

-- 
Cheers,

David


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/4] mm: Fix page-table teardown during memory hot-remove
  2026-10-08  7:30 [PATCH 0/4] mm: Fix page-table teardown during memory hot-remove Muchun Song
                   ` (3 preceding siblings ...)
  2026-10-08  7:30 ` [PATCH 4/4] arm64/mm: fix destructor for unconstructed hotplug page tables Muchun Song
@ 2026-10-09 20:48 ` Dave Hansen
  4 siblings, 0 replies; 16+ messages in thread
From: Dave Hansen @ 2026-10-09 20:48 UTC (permalink / raw)
  To: Muchun Song, akpm
  Cc: linux-mm, stable, david, osalvador, dave.hansen, luto, peterz,
	tglx, mingo, bp, x86, hpa, catalin.marinas, will, mark.rutland,
	linux-arm-kernel, pjw, palmer, aou, alex, linux-riscv, agordeev,
	kevin.brodsky, bjorn, apopple, linux-kernel, muchun.song

On 10/8/26 00:30, Muchun Song wrote:
> This series is limited to bug fixes for the existing teardown paths.

Why is this a series? Why not send the architectures independently? Is
there some dependency where they all need to be applied at once? What do
you want done with this series? Are you expecting it to be merged via
the mm path or the individual arch maintainers?


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/4] x86/mm: fix missing pgtable destructor for vmemmap tables
  2026-10-08  7:30 ` [PATCH 1/4] x86/mm: fix missing pgtable destructor for vmemmap tables Muchun Song
  2026-10-08  8:32   ` Muchun Song
  2026-10-09 20:33   ` David Hildenbrand (Arm)
@ 2026-10-09 20:54   ` Dave Hansen
  2 siblings, 0 replies; 16+ messages in thread
From: Dave Hansen @ 2026-10-09 20:54 UTC (permalink / raw)
  To: Muchun Song, akpm
  Cc: linux-mm, stable, david, osalvador, dave.hansen, luto, peterz,
	tglx, mingo, bp, x86, hpa, catalin.marinas, will, mark.rutland,
	linux-arm-kernel, pjw, palmer, aou, alex, linux-riscv, agordeev,
	kevin.brodsky, bjorn, apopple, linux-kernel, muchun.song

On 10/8/26 00:30, Muchun Song wrote:
> Since commit 49f599666420 ("mm: call ctor/dtor for kernel PTEs"),
> pte_alloc_one_kernel() runs the page-table constructor for kernel PTE
> tables.
> 
> HugeTLB vmemmap optimization uses pte_alloc_one_kernel() when splitting
> a PMD. Restoring the vmemmap backing pages does not collapse the PTE
> table, so a later memory hot-remove eventually frees that table through
> free_pagetable(). That path currently calls pagetable_free() directly
> without decrementing NR_PAGETABLE.
> 
> Use PageTable() to identify constructor-backed tables and run the
> matching destructor before freeing them. Keep reserved and
> constructor-free tables on their existing paths. This also prepares
> vmemmap teardown for generic runtime allocations through the normal
> pgalloc helpers.

Could you please take some time and trim the bits out of this changelog
that the LLM inserted but that are not super relevant? For instance, I'm
not sure what the first paragraph is trying to say. It is apparently
missing some context.

FWIW, I really don't like the LLM changelogs on their own. They almost
inevitably need human editing to make them usable. I really, really
expect humans that are sending x86 patches to spend some human
brainpower on them. In fact, I expect folks with:

	Assisted-by: LLM

to be sending _impeccable_ changelogs in v1 because their LLM saved them
so much time that they can spend gobs on their changelogs. More than
ever. ;)

Oh, and it's an x86 crime that we have:

	free_pagetable()
and
	pagetable_free()

Any work that makes that coherent would be much appreciated.


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2026-10-09 20:54 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-08  7:30 [PATCH 0/4] mm: Fix page-table teardown during memory hot-remove Muchun Song
2026-10-08  7:30 ` [PATCH 1/4] x86/mm: fix missing pgtable destructor for vmemmap tables Muchun Song
2026-10-08  8:32   ` Muchun Song
2026-10-09 20:29     ` David Hildenbrand (Arm)
2026-10-09 20:33   ` David Hildenbrand (Arm)
2026-10-09 20:36     ` David Hildenbrand (Arm)
2026-10-09 20:54   ` Dave Hansen
2026-10-08  7:30 ` [PATCH 2/4] riscv/mm: fix hotplug page-table destructor handling Muchun Song
2026-10-09  6:09   ` Björn Töpel
2026-10-09 14:14     ` Muchun Song
2026-10-09 20:37   ` David Hildenbrand (Arm)
2026-10-08  7:30 ` [PATCH 3/4] riscv/mm: fix missing destructor for hotplug PUD tables Muchun Song
2026-10-09 20:38   ` David Hildenbrand (Arm)
2026-10-08  7:30 ` [PATCH 4/4] arm64/mm: fix destructor for unconstructed hotplug page tables Muchun Song
2026-10-09 20:43   ` David Hildenbrand (Arm)
2026-10-09 20:48 ` [PATCH 0/4] mm: Fix page-table teardown during memory hot-remove Dave Hansen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox