[PATCH] mm/hugetlb: restore failed global reservations to subpool in alloc_hugetlb_folio
From: Song Hu
Date: Mon Jul 13 2026 - 07:51:29 EST
When hugetlb_alloc_folio() fails, alloc_hugetlb_folio() only rolls back
spool->used_hpages in the out_subpool_put path when gbl_chg == 0. For
gbl_chg > 0 (e.g. a size= hugetlbfs mount), hugepage_subpool_get_pages()
has already incremented used_hpages, but the error path skips the
rollback, so each failed fault permanently leaks one used_hpage until
the subpool is exhausted and hugepage_subpool_get_pages() itself fails.
Decrement used_hpages for the gbl_chg > 0 case too, mirroring the
hugetlb_reserve_pages() fix.
Fixes: a833a693a490 ("mm: hugetlb: fix incorrect fallback for subpool")
Signed-off-by: Song Hu <husong@xxxxxxxxxx>
---
mm/hugetlb.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index d6c812d1857b..8413ec92d836 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -3073,6 +3073,19 @@ struct folio *alloc_hugetlb_folio(struct vm_area_struct *vma,
if (map_chg && !gbl_chg) {
gbl_reserve = hugepage_subpool_put_pages(spool, 1);
hugetlb_acct_memory(h, -gbl_reserve);
+ } else if (map_chg && gbl_chg > 0 && spool) {
+ /*
+ * Restore used_hpages for the globally-requested page that
+ * hugepage_subpool_get_pages() counted against the subpool's
+ * maximum, but which we failed to back from the global pool.
+ * Mirrors the fix in hugetlb_reserve_pages() (1d3f9bb4c8af).
+ */
+ unsigned long flags;
+
+ spin_lock_irqsave(&spool->lock, flags);
+ if (spool->max_hpages != -1)
+ spool->used_hpages -= gbl_chg;
+ unlock_or_release_subpool(spool, flags);
}
out_end_reservation:
--
2.43.0