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 --- 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