From: sashiko-bot@kernel.org
To: "Gregory Price (Meta)" <gourry@gourry.net>, linux-mm@kvack.org
Cc: linux-trace-kernel@vger.kernel.org,
linux-rt-devel@lists.linux.dev, kernel-team@meta.com,
akpm@linux-foundation.org, mhocko@suse.com, rientjes@google.com,
shakeel.butt@linux.dev, rostedt@goodmis.org, mhiramat@kernel.org,
mathieu.desnoyers@efficios.com, muchun.song@linux.dev,
osalvador@suse.de, david@kernel.org, ljs@kernel.org,
liam@infradead.org, vbabka@kernel.org, rppt@kernel.org,
surenb@google.com, brendan.jackman@linux.dev, hannes@cmpxchg.org,
ziy@nvidia.com, bigeasy@linutronix.de, clrkwllms@kernel.org,
mgorman@techsingularity.net, anshuman.khandual@arm.com,
Bessel.Wang@huawei.com, jiang.liu@huawei.com,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v3 5/8] mm/page_alloc: retry allocations that raced with a zonelist rebuild
Date: Thu, 22 Oct 2026 02:41:28 +0000 [thread overview]
Message-ID: <sashiko-outbox-180880@kernel.org> (raw)
In-Reply-To: <20261021023940.1940971-6-gourry@gourry.net>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] mm/page_alloc: __alloc_pages_slowpath() restart loses reserve retry
- [Medium] mm/page_alloc: post-rmqueue() zonelist retry leaves ZONE_MOVABLE blocks unmovable
--
commit 3b023f87050323ef9781701d5864437d2b2b4b5e
Author: Gregory Price (Meta) <gourry@gourry.net>
mm/page_alloc: retry allocations that raced with a zonelist rebuild
This commit checks zonelist_update_seq after page allocation succeeds in the
fast path, slowpath, and bulk allocator, freeing the allocated page and
retrying if a concurrent zonelist rebuild occurred during the zonelist walk.
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 1bb308296fcdc..dd8c9046f9a06 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
[ ... ]
> @@ -5114,6 +5127,12 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
> warn_alloc(gfp_mask, ac->nodemask,
> "page allocation failure: order:%u", order);
> got_pg:
> + /* A rebuild during the walk may have handed out an ineligible zone. */
> + if (page && check_retry_zonelist(zonelist_iter_cookie)) {
> + __free_frozen_pages(page, order, FPI_NONE);
> + page = NULL;
> + goto restart;
> + }
> return page;
> }
[Severity: Medium]
In __alloc_pages_slowpath() in mm/page_alloc.c, can_retry_reserves is
initialized to true only once before the restart: label:
bool compact_first = false;
bool can_retry_reserves = true;
unsigned long alloc_start_time = jiffies;
When a reserve-eligible allocation (such as PF_MEMALLOC, __GFP_MEMALLOC, or
an OOM victim) fails its initial get_page_from_freelist() attempt at retry:,
it sets reserve_flags in alloc_flags, clears ac->nodemask, sets
can_retry_reserves = false, and jumps to retry:
reserve_flags = __gfp_pfmemalloc_flags(gfp_mask);
if (reserve_flags)
alloc_flags = alloc_flags_cma(gfp_mask) | reserve_flags |
ac->alloc_flags | (alloc_flags & ALLOC_KSWAPD);
if (!(alloc_flags & ALLOC_CPUSET) || reserve_flags) {
ac->nodemask = NULL;
ac->preferred_zoneref = first_zones_zonelist(ac->zonelist,
ac->highest_zoneidx, ac->nodemask);
if (can_retry_reserves) {
can_retry_reserves = false;
goto retry;
}
}
If that reserve pass allocates a page and reaches got_pg: while
check_retry_zonelist(zonelist_iter_cookie) is true, the new check frees the
page and jumps to restart:.
At restart:, alloc_flags is reinitialized without reserve_flags:
alloc_flags = ac->alloc_flags | alloc_flags_slowpath(gfp_mask, order);
Because can_retry_reserves is still false (and ac->nodemask remains NULL), if
the first get_page_from_freelist() after restart: fails without
reserve_flags, the can_retry_reserves retry is skipped. Callers with
!can_direct_reclaim (for example GFP_NOWAIT | __GFP_MEMALLOC or
GFP_ATOMIC | __GFP_MEMALLOC) or current->flags & PF_MEMALLOC then jump
directly to nopage: and fail without ever retrying get_page_from_freelist()
with reserve_flags on the rebuilt zonelist.
Could jumping to restart: from got_pg: without resetting can_retry_reserves
(and restoring ac->nodemask) cause reserve-eligible allocations to lose their
reserve retry and fail spuriously?
[ ... ]
> @@ -5472,6 +5499,11 @@ struct page *__alloc_frozen_pages_noprof(gfp_t gfp, unsigned int order,
>
> /* First allocation attempt (or, for nolock, only attempt) */
> page = get_page_from_freelist(alloc_gfp, order, fastpath_alloc_flags, &ac);
> + if (likely(page) && unlikely(check_retry_zonelist(zonelist_iter_cookie))) {
> + __free_frozen_pages(page, order,
> + alloc_flags & ALLOC_NOLOCK ? FPI_NOLOCK : 0);
> + page = NULL;
> + }
> if (likely(page) || (alloc_flags & ALLOC_NOLOCK))
> goto out;
>
[Severity: Medium]
When a non-movable request (such as GFP_KERNEL with MIGRATE_UNMOVABLE or
MIGRATE_RECLAIMABLE) races with online_pages() -> build_all_zonelists() and
get_page_from_freelist() selects ZONE_MOVABLE, rmqueue() runs on ZONE_MOVABLE
before check_retry_zonelist() is checked in __alloc_frozen_pages_noprof() or
at got_pg: in __alloc_pages_slowpath().
Because ZONE_MOVABLE has no free pages in MIGRATE_UNMOVABLE,
rmqueue() -> rmqueue_pcplist() -> __rmqueue_pcplist() -> rmqueue_bulk() ->
__rmqueue() -> __rmqueue_claim() -> try_to_claim_block() claims a
MIGRATE_MOVABLE block in ZONE_MOVABLE, converts its pageblock migratetype to
start_type, and expands the remaining pages into ZONE_MOVABLE's non-movable
freelists and PCP list:
/* Take ownership for orders >= pageblock_order */
if (current_order >= pageblock_order) {
unsigned int nr_added;
del_page_from_free_list(page, zone, current_order, block_type);
change_pageblock_range(page, current_order, start_type);
nr_added = expand(zone, page, order, current_order, start_type);
account_freepages(zone, nr_added, start_type);
return page;
}
When check_retry_zonelist() then detects the race and calls
__free_frozen_pages(), __free_frozen_pages() reads the mutated pageblock
migratetype:
zone = page_zone(page);
migratetype = get_pfnblock_migratetype(page, pfn);
and frees only that single page back to ZONE_MOVABLE's MIGRATE_UNMOVABLE PCP
list or buddy freelist.
Can checking check_retry_zonelist() only after rmqueue() has already mutated
the zone leave converted MIGRATE_UNMOVABLE, MIGRATE_RECLAIMABLE, or
MIGRATE_HIGHATOMIC pageblocks and populated non-movable PCP/free lists inside
ZONE_MOVABLE, where normal movable allocations will not consume the PCP list
and compaction will skip the non-movable pageblocks?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261021023940.1940971-1-gourry@gourry.net?part=5
next prev parent reply other threads:[~2026-10-22 2:41 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-21 2:39 [PATCH v3 0/8] mm: fix allocator races with memory hotplug Gregory Price (Meta)
2026-10-21 2:39 ` [PATCH v3 1/8] mm/page_alloc: detect zonelist rebuilds from memory hot-add Gregory Price (Meta)
2026-10-21 2:39 ` [PATCH v3 2/8] mm/page_alloc: snapshot the preferred zone against shrink rebuilds Gregory Price (Meta)
2026-10-21 2:39 ` [PATCH v3 3/8] mm/mmzone: read each zoneref slot once when filtering by nodemask Gregory Price (Meta)
2026-10-21 2:39 ` [PATCH v3 4/8] mm/page_alloc: pass the zone, not the zoneref, to reclaim_retry_zone Gregory Price (Meta)
2026-10-21 2:39 ` [PATCH v3 5/8] mm/page_alloc: retry allocations that raced with a zonelist rebuild Gregory Price (Meta)
2026-10-22 2:41 ` sashiko-bot [this message]
2026-10-21 2:39 ` [PATCH v3 6/8] mm/hugetlb: retry the pool walk when the zonelist is rebuilt Gregory Price (Meta)
2026-10-21 2:39 ` [PATCH v3 7/8] mm/page_alloc: retry alloc_contig_pages() " Gregory Price (Meta)
2026-10-21 2:39 ` [PATCH v3 8/8] mm/page_alloc: keep a zone's pagesets when it goes empty Gregory Price (Meta)
2026-10-21 8:24 ` [PATCH v3 0/8] mm: fix allocator races with memory hotplug David Hildenbrand (Arm)
2026-10-21 13:24 ` Gregory Price (Meta)
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-180880@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=Bessel.Wang@huawei.com \
--cc=akpm@linux-foundation.org \
--cc=anshuman.khandual@arm.com \
--cc=bigeasy@linutronix.de \
--cc=brendan.jackman@linux.dev \
--cc=clrkwllms@kernel.org \
--cc=david@kernel.org \
--cc=gourry@gourry.net \
--cc=hannes@cmpxchg.org \
--cc=jiang.liu@huawei.com \
--cc=kernel-team@meta.com \
--cc=liam@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-rt-devel@lists.linux.dev \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=ljs@kernel.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=mgorman@techsingularity.net \
--cc=mhiramat@kernel.org \
--cc=mhocko@suse.com \
--cc=muchun.song@linux.dev \
--cc=osalvador@suse.de \
--cc=rientjes@google.com \
--cc=rostedt@goodmis.org \
--cc=rppt@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=shakeel.butt@linux.dev \
--cc=surenb@google.com \
--cc=vbabka@kernel.org \
--cc=ziy@nvidia.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
all inboxes | Powered by JetHome®