Set PG_zeroed on surplus hugetlb pages when buddy-allocated with PGHINT_ZEROED (indicating the page was pre-zeroed by the host). Clear PG_zeroed in free_huge_folio() when a user-mapped page returns to the pool.
Check PG_zeroed at fault and fallocate callers to skip redundant folio_zero_user(). Signed-off-by: Michael S. Tsirkin <[email protected]> Assisted-by: Claude:claude-opus-4-6 Assisted-by: cursor-agent:GPT-5.4-xhigh --- fs/hugetlbfs/inode.c | 5 ++++- mm/hugetlb.c | 31 +++++++++++++++++++++---------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 3f70c47981de..3f9bdb5a7c85 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -828,7 +828,10 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset, error = PTR_ERR(folio); goto out; } - folio_zero_user(folio, addr); + if (PageZeroed(&folio->page)) + __ClearPageZeroed(&folio->page); + else + folio_zero_user(folio, addr); __folio_mark_uptodate(folio); error = hugetlb_add_to_page_cache(folio, mapping, index); if (unlikely(error)) { diff --git a/mm/hugetlb.c b/mm/hugetlb.c index faa94a114fd4..704ec0817c5e 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -1746,6 +1746,8 @@ void free_huge_folio(struct folio *folio) bool restore_reserve; unsigned long flags; + __ClearPageZeroed(&folio->page); + VM_BUG_ON_FOLIO(folio_ref_count(folio), folio); VM_BUG_ON_FOLIO(folio_mapcount(folio), folio); @@ -1919,12 +1921,13 @@ static struct folio *only_alloc_fresh_hugetlb_folio(struct hstate *h, * pages is zero, and the accounting must be done in the caller. */ static struct folio *alloc_fresh_hugetlb_folio(struct hstate *h, - gfp_t gfp_mask, int nid, nodemask_t *nmask) + gfp_t gfp_mask, int nid, nodemask_t *nmask, + pghint_t *hints) { struct folio *folio; folio = only_alloc_fresh_hugetlb_folio(h, gfp_mask, nid, nmask, - NULL, NULL); + NULL, hints); if (folio) hugetlb_vmemmap_optimize_folio(h, folio); return folio; @@ -2137,6 +2140,7 @@ static struct folio *alloc_surplus_hugetlb_folio(struct hstate *h, gfp_t gfp_mask, int nid, nodemask_t *nmask) { struct folio *folio = NULL; + pghint_t hints; if (hstate_is_gigantic_no_runtime(h)) return NULL; @@ -2146,10 +2150,13 @@ static struct folio *alloc_surplus_hugetlb_folio(struct hstate *h, goto out_unlock; spin_unlock_irq(&hugetlb_lock); - folio = alloc_fresh_hugetlb_folio(h, gfp_mask, nid, nmask); + folio = alloc_fresh_hugetlb_folio(h, gfp_mask, nid, nmask, &hints); if (!folio) return NULL; + if (hints & PGHINT_ZEROED) + __SetPageZeroed(&folio->page); + spin_lock_irq(&hugetlb_lock); /* * nr_huge_pages needs to be adjusted within the same lock cycle @@ -2189,7 +2196,7 @@ static struct folio *alloc_migrate_hugetlb_folio(struct hstate *h, gfp_t gfp_mas if (hstate_is_gigantic(h)) return NULL; - folio = alloc_fresh_hugetlb_folio(h, gfp_mask, nid, nmask); + folio = alloc_fresh_hugetlb_folio(h, gfp_mask, nid, nmask, NULL); if (!folio) return NULL; @@ -2242,9 +2249,6 @@ struct folio *alloc_hugetlb_folio_reserve(struct hstate *h, int preferred_nid, { struct folio *folio; - if (hints) - *hints = (pghint_t)0; - spin_lock_irq(&hugetlb_lock); if (!h->resv_huge_pages) { spin_unlock_irq(&hugetlb_lock); @@ -2253,8 +2257,12 @@ struct folio *alloc_hugetlb_folio_reserve(struct hstate *h, int preferred_nid, folio = dequeue_hugetlb_folio_nodemask(h, gfp_mask, preferred_nid, nmask); - if (folio) + if (folio) { h->resv_huge_pages--; + if (hints) + *hints = PageZeroed(&folio->page) ? PGHINT_ZEROED : 0; + __ClearPageZeroed(&folio->page); + } spin_unlock_irq(&hugetlb_lock); return folio; @@ -2748,7 +2756,7 @@ static int alloc_and_dissolve_hugetlb_folio(struct folio *old_folio, spin_unlock_irq(&hugetlb_lock); gfp_mask = htlb_alloc_mask(h) | __GFP_THISNODE; new_folio = alloc_fresh_hugetlb_folio(h, gfp_mask, - nid, NULL); + nid, NULL, NULL); if (!new_folio) return -ENOMEM; goto retry; @@ -5820,7 +5828,10 @@ static vm_fault_t hugetlb_no_page(struct address_space *mapping, ret = 0; goto out; } - folio_zero_user(folio, vmf->real_address); + if (PageZeroed(&folio->page)) + __ClearPageZeroed(&folio->page); + else + folio_zero_user(folio, vmf->real_address); __folio_mark_uptodate(folio); new_folio = true; -- MST

