From: sashiko-bot@kernel.org
To: "Mark Bundschuh" <mkbund@amazon.com>
Cc: sashal@kernel.org, linux-mm@kvack.org, david@kernel.org,
yangge <yangge1116@126.com>,
"Baolin Wang" <baolin.wang@linux.alibaba.com>,
"Barry Song" <21cnbao@gmail.com>,
"David Hildenbrand" <david@redhat.com>,
"SeongJae Park" <sj@kernel.org>,
"Andrew Morton" <akpm@linux-foundation.org>
Subject: Re: [PATCH v2 6.6 1/2] mm: replace free hugepage folios after migration
Date: Sat, 07 Nov 2026 22:08:45 +0000 [thread overview]
Message-ID: <sashiko-outbox-203356@kernel.org> (raw)
In-Reply-To: <20261106220812.2874571-2-mkbund@amazon.com>
Thank you for your contribution! Sashiko AI review found 3 potential
issues to consider:
- [High] mm: hugetlb: skipping isolated folios in dequeue breaks resv
accounting
- [Medium] mm: hugetlb: pfn step in replace_free_hugepage_folios()
over-allocates
- [Medium] mm: hugetlb: missing free_hpage_work flush after hugetlb
migration
--
commit 001656b3d65502344f54f0dc762e32f45c183341
Author: yangge <yangge1116@126.com>
mm: replace free hugepage folios after migration
This commit skips isolated free hugetlb folios during pool dequeuing and
adds replace_free_hugepage_folios() to replace and dissolve free hugetlb
folios in the target range after migration in alloc_contig_range().
Link: https://lkml.kernel.org/r/1734503588-16254-1-git-send-email-yangge1116@126.com
Link: https://lkml.kernel.org/r/1736582300-11364-1-git-send-email-yangge1116@126.com
> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> index 8bfaaa84bb3f7..2ef28c49b9d0f 100644
> --- a/mm/hugetlb.c
> +++ b/mm/hugetlb.c
[ ... ]
> @@ -1344,6 +1345,9 @@ static struct folio *dequeue_hugetlb_folio_node_exact(struct hstate *h,
> if (folio_test_hwpoison(folio))
> continue;
>
> + if (is_migrate_isolate_page(&folio->page))
> + continue;
> +
> list_move(&folio->lru, &h->hugepage_activelist);
> folio_ref_unfreeze(folio, 1);
> folio_clear_hugetlb_freed(folio);
[Severity: High]
Does skipping isolated folios in dequeue_hugetlb_folio_node_exact() while
still counting them in h->free_huge_pages break hugetlb reservation
accounting?
available_huge_pages(h) computes h->free_huge_pages - h->resv_huge_pages,
so a free folio in a MIGRATE_ISOLATE pageblock still appears as an
available unreserved page even though it cannot be dequeued. When
alloc_hugetlb_folio_nodemask() or an unreserved fault sees
available_huge_pages(h) > 0, dequeue_hugetlb_folio_node_exact() skips the
isolated folio and consumes a non-isolated free folio that was backing
h->resv_huge_pages instead of allocating a temporary migration folio via
alloc_migrate_hugetlb_folio().
Once the reserved free folios have been replaced by isolated free folios:
1. A page fault on a VMA with a valid reservation sees
dequeue_hugetlb_folio_vma() return NULL and falls back to
alloc_buddy_hugetlb_folio_with_mpol(), which fails with -ENOSPC (and
delivers SIGBUS) whenever surplus overcommit is disabled
(nr_overcommit_huge_pages == 0 by default, or gigantic pages).
2. In offline_pages(), dissolve_free_huge_pages() dissolves the unreserved
folio (dropping available_huge_pages(h) to 0 and shrinking
h->max_huge_pages) and then fails with -EBUSY on the remaining isolated
free folios because !available_huge_pages(h).
Also, is_migrate_isolate_page(&folio->page) only checks the head pageblock
and misses isolated tail pageblocks when huge_page_order(h) >
pageblock_order.
> @@ -3048,6 +3052,44 @@ int isolate_or_dissolve_huge_page(struct page *page, struct list_head *list)
> return ret;
> }
>
> +/*
> + * replace_free_hugepage_folios - Replace free hugepage folios in a given pfn
> + * range with new folios.
> + * @start_pfn: start pfn of the given pfn range
> + * @end_pfn: end pfn of the given pfn range
> + * Returns 0 on success, otherwise negated error.
> + */
> +int replace_free_hugepage_folios(unsigned long start_pfn, unsigned long end_pfn)
> +{
> + struct hstate *h;
> + struct folio *folio;
> + int ret = 0;
> +
> + LIST_HEAD(isolate_list);
> +
> + while (start_pfn < end_pfn) {
> + folio = pfn_folio(start_pfn);
> + if (folio_test_hugetlb(folio)) {
> + h = folio_hstate(folio);
> + } else {
> + start_pfn++;
> + continue;
> + }
> +
> + if (!folio_ref_count(folio)) {
> + ret = alloc_and_dissolve_hugetlb_folio(h, folio,
> + &isolate_list);
[Severity: Medium]
When HugeTLB vmemmap optimization (HVO) is active, can
replace_free_hugepage_folios() miss temporary or surplus folios that were
just freed by __alloc_contig_migrate_range()?
Because dequeue_hugetlb_folio_node_exact() now skips isolated free folios,
hugetlb migrations in the range fall back to alloc_migrate_hugetlb_folio(),
which sets HPG_temporary. When migration finishes, free_huge_folio() frees
the old folio via update_and_free_hugetlb_folio(h, folio, true); for an HVO
folio, this keeps a reference count of 1 and queues the folio onto
hpage_freelist for free_hpage_work to restore vmemmap asynchronously.
Without flushing free_hpage_work (for example via
wait_for_freed_hugetlb_folios() or flush_free_hpage_work(h)) before
scanning the range, folio_ref_count(folio) is still 1 here and
test_pages_isolated() subsequently fails with -EBUSY because the folio has
not yet been returned to the buddy allocator.
> + if (ret)
> + break;
> +
> + putback_movable_pages(&isolate_list);
> + }
> + start_pfn++;
> + }
[Severity: Medium]
Can advancing start_pfn by 1 cause replace_free_hugepage_folios() to call
alloc_and_dissolve_hugetlb_folio() on every tail page of the same hugepage
if it was not dissolved?
In alloc_and_dissolve_hugetlb_folio(), __update_and_free_hugetlb_folio()
can fail to restore vmemmap under memory pressure and put old_folio back on
the hugetlb freelist as a surplus page with refcount 0 while still
returning 0:
mm/hugetlb.c:__update_and_free_hugetlb_folio() {
...
if (hugetlb_vmemmap_restore(h, &folio->page)) {
spin_lock_irq(&hugetlb_lock);
add_hugetlb_folio(h, folio, true);
spin_unlock_irq(&hugetlb_lock);
return;
}
...
}
Because old_folio remains a free hugetlb folio and start_pfn only increments
by 1, the loop hits the same folio on each of its remaining tail PFNs,
allocating a new replacement hugepage and incrementing h->nr_huge_pages and
h->surplus_huge_pages on every tail PFN (up to 511 extra hugepages for a
2MB folio). The same repeated scan happens if
alloc_and_dissolve_hugetlb_folio() isolates a concurrently referenced folio
into isolate_list and putback_movable_pages(&isolate_list) immediately
releases it.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261106220812.2874571-1-mkbund@amazon.com?part=1
next prev parent reply other threads:[~2026-11-07 22:08 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-05 7:04 [PATCH 6.6] mm: replace free hugepage folios after migration Mark Bundschuh
2026-11-06 7:04 ` sashiko-bot
2026-11-06 22:08 ` [PATCH v2 6.6 0/2] " Mark Bundschuh
2026-11-06 22:08 ` [PATCH v2 6.6 1/2] " Mark Bundschuh
2026-11-07 22:08 ` sashiko-bot [this message]
2026-11-06 22:08 ` [PATCH v2 6.6 2/2] mm/hugetlb: fix kernel NULL pointer dereference when replacing free hugetlb folios Mark Bundschuh
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-203356@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=21cnbao@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=baolin.wang@linux.alibaba.com \
--cc=david@kernel.org \
--cc=david@redhat.com \
--cc=linux-mm@kvack.org \
--cc=mkbund@amazon.com \
--cc=sashal@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=sj@kernel.org \
--cc=yangge1116@126.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox