mm/hugetlb: restore subpool used_hpages on alloc_hugetlb_folio error
Subsystems (3)
PATCH 1/1 mm/hugetlb: restore subpool used_hpages on alloc_hugetlb_folio error
Commit a833a693a490 added a !gbl_chg guard around the hugepage_subpool_put_pages() call in alloc_hugetlb_folio()'s out_subpool_put path so a failed allocation wouldn't drive h->resv_huge_pages negative. But hugepage_subpool_get_pages() increments spool->used_hpages whenever max_hpages != -1, regardless of whether the request was satisfied from subpool reserves or needs global pages. When gbl_chg > 0 and a later step fails (cgroup charge, dequeue, buddy alloc), used_hpages is never put back.
Each such failure leaks one count; eventually used_hpages reaches max_hpages and the subpool refuses every further allocation even though no pages are held.
Commit 1d3f9bb4c8af fixed the same defect in hugetlb_reserve_pages(); apply the equivalent restore here, guarded by spool and max_hpages.
--- mm/hugetlb.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)
mm/hugetlb.c +16 -3
@@ -3010,9 +3010,22 @@ struct folio *alloc_hugetlb_folio(struct vm_area_struct *vma,* put page to subpool iff the quota of subpool's rsv_hpages is used * during hugepage_subpool_get_pages. */ -if (map_chg && !gbl_chg) { - gbl_reserve =hugepage_subpool_put_pages (spool,1 ); -hugetlb_acct_memory (h, -gbl_reserve); +if (map_chg) { +/* +* Put used_hpages back for the global portion of the request that +* was never actually consumed; restore the subpool-reservation +* portion via hugepage_subpool_put_pages() so rsv_hpages is rebuilt. +*/ +if (!gbl_chg) { + gbl_reserve =hugepage_subpool_put_pages (spool,1 ); +hugetlb_acct_memory (h, -gbl_reserve); + }else if (spool && spool->max_hpages !=-1 ) { +unsigned long flags; + +spin_lock_irqsave (&spool->lock, flags); + spool->used_hpages -=1 ; +unlock_or_release_subpool (spool, flags); + } }
Signature · 1 line
2.53.0
Quoted 9 lines · On Fri, 15 May 2026 21:29:02 +0100 David Carlier <[email protected]> wrote:
Commit
a833a693a490added a !gbl_chg guard around thehugepage_subpool_put_pages()call in alloc_hugetlb_folio()'sout_subpool_putpath so a failed allocation wouldn't driveh->resv_huge_pagesnegative. Buthugepage_subpool_get_pages()incrementsspool->used_hpageswhenevermax_hpages!= -1, regardless of whether the request was satisfied from subpool reserves or needs global pages. Whengbl_chg> 0 and a later step fails (cgroup charge, dequeue, buddy alloc),used_hpagesis never put back.
Quoted 6 lines
Each such failure leaks one count; eventually
used_hpagesreachesmax_hpagesand the subpool refuses every further allocation even though no pages are held.Commit
1d3f9bb4c8affixed the same defect inhugetlb_reserve_pages(); apply the equivalent restore here, guarded by spool andmax_hpages.
Hello David,
Thank you for the patch!
I noticed that this patch is quite similar to Zhao Li's patch [1] which seems to address the same problem. Have you taken a look at his approach? From what I can tell, the code change is also quite similar (except comments and additional guards in the else if branch).
Just wanted to bring it to your attention in case you haven't seen it yet.
Have a great day!
Joshua
[1] https://lore.kernel.org/linux-mm/[email protected]/
Quoted 44 lines
Fixes a833a693a490 ("mm: hugetlb: fix incorrect fallback for subpool")Signed-off-by David Carlier <[email protected]>Cc Joshua Hahn <[email protected]>Cc Wupeng Ma <[email protected]>Cc Oscar Salvador <[email protected]>Cc Muchun Song <[email protected]>Cc David Hildenbrand <[email protected]>Cc <[email protected]>--- mm/hugetlb.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)mm/hugetlb.c +16
-3@@ -3010,9 +3010,22 @@ struct folio *alloc_hugetlb_folio(struct vm_area_struct *vma,* put page to subpool iff the quota of subpool's rsv_hpages is used * during hugepage_subpool_get_pages. */ -if (map_chg && !gbl_chg) { - gbl_reserve =hugepage_subpool_put_pages (spool,1 ); -hugetlb_acct_memory (h, -gbl_reserve); +if (map_chg) { +/* +* Put used_hpages back for the global portion of the request that +* was never actually consumed; restore the subpool-reservation +* portion via hugepage_subpool_put_pages() so rsv_hpages is rebuilt. +*/ +if (!gbl_chg) { + gbl_reserve =hugepage_subpool_put_pages (spool,1 ); +hugetlb_acct_memory (h, -gbl_reserve); + }else if (spool && spool->max_hpages !=-1 ) { +unsigned long flags; + +spin_lock_irqsave (&spool->lock, flags); + spool->used_hpages -=1 ; +unlock_or_release_subpool (spool, flags); + } }Signature · 1 line
2.53.0