Re: [PATCH v3 4/4] arm64/mm: fix destructor for unconstructed hotplug page tables

From: Anshuman Khandual

Date: Fri Oct 23 2026 - 06:21:55 EST


On Fri, Oct 23, 2026 at 02:34:28PM +0800, 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. Freeing one during memory hot-remove therefore
> runs a destructor without a matching constructor and corrupts
> NR_PAGETABLE accounting.
>
> Free intermediate page-table pages through pagetable_free(). It runs the
> destructor only for constructor-backed pages and then releases the page
> through the page-table freeing path.
>
> Fixes: c594b83457cc ("arm64: mm: call pagetable dtor when freeing hot-removed page tables")
> Cc: stable@xxxxxxxxxxxxxxx
> Assisted-by: LLM
> Signed-off-by: Muchun Song <songmuchun@xxxxxxxxxxxxx>
> Reviewed-by: Kevin Brodsky <kevin.brodsky@xxxxxxx>
> Acked-by: David Hildenbrand (Arm) <david@xxxxxxxxxx>

Reviewed-by: Anshuman Khandual <anshuman.khandual@xxxxxxx>

> ---
> v3:
> - Collect Acked-by from David Hildenbrand
> - Collect Reviewed-by from Kevin Brodsky
>
> v2:
> - Free intermediate tables through pagetable_free() (suggested by David
> Hildenbrand)
> - Update the commit message for the page-table freeing path
> ---
> arch/arm64/mm/mmu.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 79d90226fd5d..4dce8fa227c3 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -1495,8 +1495,7 @@ 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));
> - free_hotplug_page_range(page, PAGE_SIZE, NULL);
> + pagetable_free(page_ptdesc(page));
> }
>
> static bool pgtable_range_aligned(unsigned long start, unsigned long end,
> --
> 2.54.0
>