Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Mark Bundschuh" <mkbund@amazon.com>
Cc: 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 5.15] mm: replace free hugepage folios after migration
Date: Fri, 06 Nov 2026 07:03:53 +0000	[thread overview]
Message-ID: <sashiko-outbox-200952@kernel.org> (raw)
In-Reply-To: <20261105070206.3094675-1-mkbund@amazon.com>

Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [High] mm/hugetlb: isolated free pages in free_huge_pages break
  reservations and offline
- [Medium] mm: missing free hugepage replacement after migration in
  alloc_contig_range()
--

commit c4fd411e1512176c3c86e8729268c9e64aee0792
Author: yangge <yangge1116@126.com>

mm: replace free hugepage folios after migration

This backport takes the dequeue_huge_page_node_exact() hunk from upstream
commit 04f13d241b8b146b23038bffd907cb8278391d07 so that free hugetlb pages
in MIGRATE_ISOLATE pageblocks are skipped when allocating from the hugetlb
pool.

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

[Severity: Medium]
In mm/hugetlb.c, dequeue_huge_page_node_exact() is updated to skip pages
where is_migrate_isolate_page(page) is true, while the commit subject and
changelog state that replace_free_hugepage_folios() is introduced and
invoked after migrating in-use hugetlb pages so cma_alloc() and
test_pages_isolated() succeed.

In 5.15, hugetlb pages are allocated with GFP_HIGHUSER_MOVABLE via
htlb_alloc_mask() and can reside in MIGRATE_CMA and MIGRATE_MOVABLE
pageblocks. During cma_alloc() -> alloc_contig_range() ->
__alloc_contig_migrate_range() in mm/page_alloc.c,
isolate_or_dissolve_huge_page() in mm/hugetlb.c dissolves free hugepages in
the target range via alloc_and_dissolve_huge_page(), but for in-use
hugepages (page_count(head) > 0) it isolates them onto cc->migratepages via
isolate_hugetlb() and advances cc->migrate_pfn past them.

When migrate_pages() migrates those in-use hugepages via
alloc_migration_target() -> alloc_huge_page_nodemask(), if unreserved free
hugepages exist in the pool (h->free_huge_pages - h->resv_huge_pages > 0),
dequeue_huge_page_nodemask() returns a free pool hugepage without
HPageTemporary set. Because HPageTemporary(newpage) is false,
move_hugetlb_state() does not set HPageTemporary on the old source page, so
free_huge_page() enqueues the old page back onto h->hugepage_freelists[nid]
inside the MIGRATE_ISOLATE range instead of returning it to the buddy
allocator.

Because this backport omits the post-migration replacement step after
__alloc_contig_migrate_range() (even though alloc_and_dissolve_huge_page()
already exists in mm/hugetlb.c), won't migrating in-use persistent hugetlb
pages still leave the freed source hugepages on h->hugepage_freelists
inside [start, end) and cause test_pages_isolated() in alloc_contig_range()
to fail with -EBUSY? Also, should the commit subject and message be updated
if only the dequeue_huge_page_node_exact() change is intended?

[Severity: High]
In mm/hugetlb.c, dequeue_huge_page_node_exact() skips pages where
is_migrate_isolate_page(page) is true, but those isolated pages remain on
h->hugepage_freelists[nid] and remain counted in h->free_huge_pages. Can
this cause both memory offlining (offline_pages()) and reserved hugetlb
page faults (alloc_huge_page()) to fail when free hugepages sit in a
MIGRATE_ISOLATE range?

Consider a memory block [start_pfn, end_pfn) being offlined via
offline_pages() that contains two in-use hugepages H0 and H1 (or one free
hugepage H0 and one in-use hugepage H1), while outside the block there is
one unreserved free hugepage F0 and one reserved free hugepage F1 backing
an existing reservation (h->free_huge_pages == 2, h->resv_huge_pages == 1):

1. offline_pages() calls start_isolate_page_range(), marking
   [start_pfn, end_pfn) as MIGRATE_ISOLATE, and then calls
   do_migrate_range().

2. Migrating H0 dequeues F0. When H0 is released via
   putback_active_hugepage() -> free_huge_page() -> enqueue_huge_page(), H0
   is placed onto h->hugepage_freelists[nid] inside the MIGRATE_ISOLATE
   range and increments h->free_huge_pages back to 2.

3. When migrating H1, alloc_huge_page_nodemask() in mm/hugetlb.c checks:

       if (h->free_huge_pages - h->resv_huge_pages > 0)

   Because the isolated page H0 is still counted in h->free_huge_pages,
   2 - 1 > 0 succeeds even though the only non-isolated free page (F1) is
   needed to back h->resv_huge_pages.

4. dequeue_huge_page_node_exact() skips H0 because
   is_migrate_isolate_page(H0) is true and dequeues the reserved page F1
   for H1. H1 is then freed onto h->hugepage_freelists[nid] inside the
   MIGRATE_ISOLATE range, leaving both free hugepages (H0 and H1) inside
   the MIGRATE_ISOLATE range while h->resv_huge_pages == 1.

5. In offline_pages(), dissolve_free_huge_pages(start_pfn, end_pfn)
   dissolves H0 (reducing h->free_huge_pages to 1) and then calls
   dissolve_free_huge_page() on H1, which hits:

       if (h->free_huge_pages - h->resv_huge_pages == 0)
           goto out;

   and fails with -EBUSY, aborting offline_pages().

In addition, gather_surplus_pages() in mm/hugetlb.c computes:

    needed = (h->resv_huge_pages + delta) - h->free_huge_pages;
    if (needed <= 0) {
        h->resv_huge_pages += delta;
        return 0;
    }

which counts MIGRATE_ISOLATE free pages in h->free_huge_pages as usable to
satisfy reservations. Whenever the free pages backing h->resv_huge_pages
are in MIGRATE_ISOLATE pageblocks (either from migration swapping F1 with
H1 above, or from gather_surplus_pages()), a page fault on a VMA with a
valid reservation calls alloc_huge_page() -> dequeue_huge_page_vma(), which
skips the isolated pages in dequeue_huge_page_node_exact() and returns
NULL.

alloc_huge_page() then falls back to alloc_buddy_huge_page_with_mpol() ->
alloc_surplus_huge_page(), which fails when h->surplus_huge_pages >=
h->nr_overcommit_huge_pages (0 by default) or hstate_is_gigantic(h),
returning ERR_PTR(-ENOSPC) and delivering SIGBUS to a process faulting on a
reserved mapping.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261105070206.3094675-1-mkbund@amazon.com?part=1


  reply	other threads:[~2026-11-06  7:03 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-05  7:02 [PATCH 5.15] mm: replace free hugepage folios after migration Mark Bundschuh
2026-11-06  7:03 ` sashiko-bot [this message]
2026-11-06  7:46 ` David Hildenbrand (Arm)
2026-11-06 22:04 ` [PATCH v2 5.15 0/2] " Mark Bundschuh
2026-11-06 22:04   ` [PATCH v2 5.15 1/2] " Mark Bundschuh
2026-11-07 22:05     ` sashiko-bot
2026-11-06 22:04   ` [PATCH v2 5.15 2/2] mm/hugetlb: fix kernel NULL pointer dereference when replacing free hugetlb folios Mark Bundschuh
2026-11-07 22:05     ` sashiko-bot

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-200952@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=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