From: Kiryl Shutsemau <kas@kernel.org>
To: Dev Jain <dev.jain@arm.com>
Cc: "Vlastimil Babka (SUSE)" <vbabka@kernel.org>,
Johannes Weiner <hannes@cmpxchg.org>,
Andrew Morton <akpm@linux-foundation.org>,
David Hildenbrand <david@kernel.org>,
Harry Yoo <harry@kernel.org>, Usama Arif <usama.arif@linux.dev>,
Suren Baghdasaryan <surenb@google.com>,
Michal Hocko <mhocko@suse.com>,
Brendan Jackman <brendan.jackman@linux.dev>,
Zi Yan <ziy@nvidia.com>, Shakeel Butt <shakeel.butt@linux.dev>,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
stable@vger.kernel.org, kernel-team@meta.com
Subject: Re: [PATCH v3] mm: page_alloc: make defrag_mode retries follow the promoted order
Date: Fri, 23 Oct 2026 11:59:01 +0100 [thread overview]
Message-ID: <ats7oFM-fsYdUS8y@thinkstation> (raw)
In-Reply-To: <d2b8edf0-39ab-4a44-bd0d-58230dee2fad@arm.com>
On Fri, Oct 23, 2026 at 12:09:07PM +0530, Dev Jain wrote:
> >> I ran a synthetic benchmark faulting in lots of 64k mTHP with swap enabled,
> >> defrag mode caused me to enter a warn_alloc (and 8 times more compact_stalls),
> >> which didn't happen without defrag.
Thanks for the benchmark. It reproduces on x86 in the same shape.
I think I found the problem.
Under pressure, the free order-4+ pages left are mostly in partly used
unmovable and reclaimable pageblocks. A movable request with
ALLOC_NOFRAGMENT cannot take them. But compaction_suit_allocation_order()
asks __zone_watermark_ok(), which counts free pages of every
migratetype, and returns COMPACT_SUCCESS without compacting anything.
The allocation then fails, and since compaction "succeeded", it is never
deferred.
With the diff below, compaction behaves the same with and without
defrag_mode. Medians of 15 runs of "compact-bench 99 64 16 20 0":
defrag_mode=0 defrag_mode=1 defrag_mode=1
+ diff
compact_stall 2135 32476 2290
compact_fail 668 32330 606
64K anon_fault_alloc 20689 6780 11804
64K anon_fault_fallback 776 14502 9687
64K allocation is still lower with defrag_mode. I will look into this
further.
Could you try the diff on your setup?
diff --git a/mm/compaction.c b/mm/compaction.c
index a049415512c6..09be677fff36 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -2365,6 +2365,10 @@ static enum compact_result __compact_finished(struct compact_control *cc)
!free_area_empty(area, MIGRATE_CMA))
return COMPACT_SUCCESS;
#endif
+ /* Under ALLOC_NOFRAGMENT it may only claim a whole block */
+ if ((cc->alloc_flags & ALLOC_NOFRAGMENT) && order < pageblock_order)
+ continue;
+
/*
* Job done if allocation would steal freepages from
* other migratetype buddy lists.
@@ -2510,6 +2514,43 @@ bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
return false;
}
+/*
+ * The watermark check counts free pages of every migratetype. Under
+ * ALLOC_NOFRAGMENT, a request below pageblock_order cannot take a page from a
+ * block of another migratetype unless it claims the whole block, so look for
+ * a free page the request can actually use.
+ */
+static bool compaction_free_page_usable(struct zone *zone, unsigned int order,
+ int migratetype, unsigned int alloc_flags)
+{
+ unsigned int o;
+ int mt;
+
+ if (!(alloc_flags & ALLOC_NOFRAGMENT) || order >= pageblock_order)
+ return true;
+
+ for (o = order; o < NR_PAGE_ORDERS; o++) {
+ struct free_area *area = &zone->free_area[o];
+
+ if (!free_area_empty(area, migratetype))
+ return true;
+#ifdef CONFIG_CMA
+ if ((alloc_flags & ALLOC_CMA) &&
+ !free_area_empty(area, MIGRATE_CMA))
+ return true;
+#endif
+ /* From pageblock_order up, a free block can be claimed */
+ if (o < pageblock_order)
+ continue;
+ for (mt = 0; mt < MIGRATE_PCPTYPES; mt++) {
+ if (!free_area_empty(area, mt))
+ return true;
+ }
+ }
+
+ return false;
+}
+
/*
* Should we do compaction for target allocation order.
* Return COMPACT_SUCCESS if allocation for target order can be already
@@ -2520,7 +2561,7 @@ bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
static enum compact_result
compaction_suit_allocation_order(struct zone *zone, unsigned int order,
int highest_zoneidx, unsigned int alloc_flags,
- bool async, bool kcompactd)
+ int migratetype, bool async, bool kcompactd)
{
unsigned long free_pages;
unsigned long watermark;
@@ -2532,7 +2573,8 @@ compaction_suit_allocation_order(struct zone *zone, unsigned int order,
watermark = wmark_pages(zone, alloc_flags & ALLOC_WMARK_MASK);
if (__zone_watermark_ok(zone, order, watermark, highest_zoneidx,
- alloc_flags, free_pages))
+ alloc_flags, free_pages) &&
+ compaction_free_page_usable(zone, order, migratetype, alloc_flags))
return COMPACT_SUCCESS;
/*
@@ -2588,6 +2630,7 @@ compact_zone(struct compact_control *cc, struct capture_control *capc)
ret = compaction_suit_allocation_order(cc->zone, cc->order,
cc->highest_zoneidx,
cc->alloc_flags,
+ cc->migratetype,
cc->mode == MIGRATE_ASYNC,
!cc->direct_compaction);
if (ret != COMPACT_CONTINUE)
@@ -3073,7 +3116,7 @@ static bool kcompactd_node_suitable(pg_data_t *pgdat)
ret = compaction_suit_allocation_order(zone,
pgdat->kcompactd_max_order,
highest_zoneidx, alloc_flags,
- false, true);
+ MIGRATE_MOVABLE, false, true);
if (ret == COMPACT_CONTINUE)
return true;
}
@@ -3116,7 +3159,7 @@ static void kcompactd_do_work(pg_data_t *pgdat)
ret = compaction_suit_allocation_order(zone,
cc.order, zoneid, cc.alloc_flags,
- false, true);
+ MIGRATE_MOVABLE, false, true);
if (ret != COMPACT_CONTINUE)
continue;
--
Kiryl Shutsemau / Kirill A. Shutemov
next prev parent reply other threads:[~2026-10-23 10:59 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-09 12:55 Kiryl Shutsemau (Meta)
2026-10-09 14:05 ` Usama Arif
2026-10-10 22:49 ` Andrew Morton
2026-10-12 10:17 ` Kiryl Shutsemau
2026-10-12 11:40 ` Vlastimil Babka (SUSE)
2026-10-13 2:28 ` Andrew Morton
2026-10-13 17:37 ` Kiryl Shutsemau
2026-10-13 18:15 ` Vlastimil Babka (SUSE)
2026-10-14 20:29 ` Johannes Weiner
2026-10-15 7:16 ` Vlastimil Babka (SUSE)
2026-10-15 12:55 ` Kiryl Shutsemau
2026-10-15 13:53 ` Vlastimil Babka (SUSE)
2026-10-15 14:39 ` Kiryl Shutsemau
2026-10-19 6:58 ` Dev Jain
2026-10-21 9:33 ` Kiryl Shutsemau
2026-10-23 6:39 ` Dev Jain
2026-10-23 10:59 ` Kiryl Shutsemau [this message]
2026-10-15 12:50 ` Kiryl Shutsemau
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=ats7oFM-fsYdUS8y@thinkstation \
--to=kas@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=brendan.jackman@linux.dev \
--cc=david@kernel.org \
--cc=dev.jain@arm.com \
--cc=hannes@cmpxchg.org \
--cc=harry@kernel.org \
--cc=kernel-team@meta.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=mhocko@suse.com \
--cc=shakeel.butt@linux.dev \
--cc=stable@vger.kernel.org \
--cc=surenb@google.com \
--cc=usama.arif@linux.dev \
--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®