[PATCH v2 0/2] mm/hugetlb: fix surplus accounting and availability checks during demotion

From: Longlong Xia

Date: Mon Aug 31 2026 - 10:31:27 EST


From: Longlong Xia <xialonglong@xxxxxxxxxx>

This is v2 of the two-patch series fixing surplus accounting and
availability checks in the hugetlb demote path.

Patch 1 fixes source hstate accounting when the free folio selected for
demotion accounts for a surplus page. Patch 2 prevents demotion from
removing free huge pages that back reservations.

Both fixes were tested with x86_64 QEMU guests. The commands below use:

hstate=/sys/kernel/mm/hugepages/hugepages-1048576kB

Patch 1: surplus accounting

A vmemmap restoration failure is difficult to trigger deterministically.
For this test only, add a one-shot fault injection that makes the first
attempt to restore the vmemmap of an optimized 1 GiB folio fail:

/* TEST ONLY: fail the first optimized 1G folio restore. */
static atomic_t fail_next_1g_restore = ATOMIC_INIT(1);

/* In __hugetlb_vmemmap_restore_folio(). */
if (huge_page_size(h) == SZ_1G &&
atomic_cmpxchg(&fail_next_1g_restore, 1, 0) == 1) {
pr_info("TEST ONLY: forcing one 1G vmemmap "
"restore failure\n");
return -ENOMEM;
}

The injection does not modify the demotion or accounting code. It is
one-shot so that the later restore performed during demotion can succeed.

1. Boot QEMU with:

hugepagesz=1G hugepages=0 hugetlb_cma=1G
hugetlb_free_vmemmap=on

2. Enable overcommit:

echo 1 > "$hstate/nr_overcommit_hugepages"

3. Allocate one 1 GiB huge page:

nr=1 surplus=1 free=0 resv=0

4. Unmap it. The forced restoration failure leaves the folio on the
freelist while it is still accounted as surplus:

nr=1 surplus=1 free=1 resv=0

5. Demote one page:

echo 1 > "$hstate/demote"

Before this fix:

nr=0 surplus=1 free=0 resv=0
surplus > nr

After this fix:

nr=0 surplus=0 free=0 resv=0

Patch 2: cap demotion

This reproducer requires no kernel instrumentation.

1. Boot QEMU with:

hugepagesz=1G hugepages=2
nr=2 surplus=0 free=2 resv=0

2. Reserve one 1 GiB huge page with an untouched hugetlbfs mapping:

nr=2 surplus=0 free=2 resv=1

3. Request demotion of two pages:

echo 2 > "$hstate/demote"

Before this fix:

nr=0 surplus=0 free=0 resv=1
resv > free

After this fix:

nr=1 surplus=0 free=1 resv=1
resv == free

4. Touch the reserved page and let the process exit.

Before this fix, the access fails with SIGBUS and leaves:

nr=0 surplus=0 free=0 resv=0

After this fix, the access succeeds and leaves:

nr=1 surplus=0 free=1 resv=0

Changes in v2:
- Add reproducer details and test results suggested by Andrew Morton.

Link: https://lore.kernel.org/all/20260823034307.1072415-1-xialonglong2025@xxxxxxx/

Longlong Xia (2):
mm/hugetlb: preserve source surplus accounting during demotion
mm/hugetlb: cap demotion at currently available free pages

mm/hugetlb.c | 57 ++++++++++++++++++++++++++++++++++++++++++----
mm/hugetlb_sysfs.c | 10 ++++----
2 files changed, 57 insertions(+), 10 deletions(-)


base-commit: a4ff2be345d0abc943da8dd8da98151843b750dc
--
2.43.0