| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/23 16:16 | flow | patch-triage |
2mArgs:null Results: {
"EnableConfigs": [
"COMPACTION"
],
"FocusSymbols": [
"__alloc_pages_direct_compact",
"__alloc_pages_direct_reclaim",
"try_to_compact_pages",
"fast_find_migrateblock",
"suitable_migration_source"
],
"Reasoning": "The patch modifies memory compaction and direct reclaim logic, specifically how `capture_control` is handled and how allocation orders are promoted for non-movable allocations with `ALLOC_NOFRAGMENT`. This is reachable core kernel logic triggered by high-order allocations under memory fragmentation.",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/23 16:16 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 71bc7fd1f561b1d61c7a5c7564dcd89d538f8141\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Thu Jul 23 16:16:35 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/include/linux/compaction.h b/include/linux/compaction.h\nindex f29ef0653546ed..66a2f70e9e019d 100644\n--- a/include/linux/compaction.h\n+++ b/include/linux/compaction.h\n@@ -58,6 +58,7 @@ enum compact_result {\n };\n \n struct alloc_context; /* in mm/internal.h */\n+struct capture_control; /* in mm/internal.h */\n \n /*\n * Number of free order-0 pages that should be available above given watermark\n@@ -92,7 +93,7 @@ extern int fragmentation_index(struct zone *zone, unsigned int order);\n extern enum compact_result try_to_compact_pages(gfp_t gfp_mask,\n \t\tunsigned int order, unsigned int alloc_flags,\n \t\tconst struct alloc_context *ac, enum compact_priority prio,\n-\t\tstruct page **page);\n+\t\tstruct capture_control *capc);\n extern void reset_isolation_suitable(pg_data_t *pgdat);\n extern bool compaction_suitable(struct zone *zone, int order,\n \t\t\t\tunsigned long watermark, int highest_zoneidx);\ndiff --git a/mm/compaction.c b/mm/compaction.c\nindex f08765ade014ce..977e30b3a2bd16 100644\n--- a/mm/compaction.c\n+++ b/mm/compaction.c\n@@ -1381,12 +1381,44 @@ static bool suitable_migration_source(struct compact_control *cc,\n \tif (pageblock_skip_persistent(page))\n \t\treturn false;\n \n-\tif ((cc-\u003emode != MIGRATE_ASYNC) || !cc-\u003edirect_compaction)\n+\t/*\n+\t * Background compaction produces blocks for the zone at\n+\t * large, with no particular allocation context. Allow all\n+\t * block types, including CMA.\n+\t */\n+\tif (!cc-\u003edirect_compaction)\n \t\treturn true;\n \n \tblock_mt = get_pageblock_migratetype(page);\n \n-\tif (cc-\u003emigratetype == MIGRATE_MOVABLE)\n+\t/*\n+\t * CMA pages can only be taken by ALLOC_CMA requests. For anybody\n+\t * else, vacating a CMA block consumes free pages the caller\n+\t * could have used, and produces free pages it cannot.\n+\t */\n+\tif (is_migrate_cma(block_mt) \u0026\u0026 !(cc-\u003ealloc_flags \u0026 ALLOC_CMA))\n+\t\treturn false;\n+\n+\t/*\n+\t * Per default, scans are restricted to blocks compatible with\n+\t * the request, to prevent cross-contamination. Once\n+\t * compaction priority escalates to synchronous scans, though,\n+\t * scan all blocks to try to make forward progress. For\n+\t * movable request, this likely helps little: there shouldn't\n+\t * be many migratable pages inside non-movable blocks besides\n+\t * allocator fallbacks. For non-movable requests, this helps a\n+\t * lot, as they can finally scan movable blocks.\n+\t */\n+\tif (cc-\u003emode != MIGRATE_ASYNC)\n+\t\treturn true;\n+\n+\t/*\n+\t * Prevent \u003cpageblock_order unmovable/reclaimable requests from\n+\t * polluting movable blocks through fallbacks. Whole-block production\n+\t * (directly requested, or defrag_mode) is exempt as the allocator\n+\t * claims and converts these.\n+\t */\n+\tif (cc-\u003emigratetype == MIGRATE_MOVABLE || cc-\u003eorder \u003e= pageblock_order)\n \t\treturn is_migrate_movable(block_mt);\n \telse\n \t\treturn block_mt == cc-\u003emigratetype;\n@@ -1974,12 +2006,12 @@ static unsigned long fast_find_migrateblock(struct compact_control *cc)\n \t\treturn pfn;\n \n \t/*\n-\t * Only allow kcompactd and direct requests for movable pages to\n-\t * quickly clear out a MOVABLE pageblock for allocation. This\n-\t * reduces the risk that a large movable pageblock is freed for\n-\t * an unmovable/reclaimable small allocation.\n+\t * Prevent \u003cpageblock_order unmovable/reclaimable requests from\n+\t * polluting movable blocks through fallbacks. Whole-block production\n+\t * is exempt as the allocator claims and converts these.\n \t */\n-\tif (cc-\u003edirect_compaction \u0026\u0026 cc-\u003emigratetype != MIGRATE_MOVABLE)\n+\tif (cc-\u003edirect_compaction \u0026\u0026 cc-\u003emigratetype != MIGRATE_MOVABLE \u0026\u0026\n+\t cc-\u003eorder \u003c pageblock_order)\n \t\treturn pfn;\n \n \t/*\n@@ -2770,9 +2802,8 @@ compact_zone(struct compact_control *cc, struct capture_control *capc)\n static enum compact_result compact_zone_order(struct zone *zone, int order,\n \t\tgfp_t gfp_mask, enum compact_priority prio,\n \t\tunsigned int alloc_flags, int highest_zoneidx,\n-\t\tstruct page **capture)\n+\t\tstruct capture_control *capc)\n {\n-\tenum compact_result ret;\n \tstruct compact_control cc = {\n \t\t.order = order,\n \t\t.search_order = order,\n@@ -2787,38 +2818,8 @@ static enum compact_result compact_zone_order(struct zone *zone, int order,\n \t\t.ignore_skip_hint = (prio == MIN_COMPACT_PRIORITY),\n \t\t.ignore_block_suitable = (prio == MIN_COMPACT_PRIORITY)\n \t};\n-\tstruct capture_control capc = {\n-\t\t.cc = \u0026cc,\n-\t\t.page = NULL,\n-\t};\n \n-\t/*\n-\t * Make sure the structs are really initialized before we expose the\n-\t * capture control, in case we are interrupted and the interrupt handler\n-\t * frees a page.\n-\t */\n-\tbarrier();\n-\tWRITE_ONCE(current-\u003ecapture_control, \u0026capc);\n-\n-\tret = compact_zone(\u0026cc, \u0026capc);\n-\n-\t/*\n-\t * Make sure we hide capture control first before we read the captured\n-\t * page pointer, otherwise an interrupt could free and capture a page\n-\t * and we would leak it.\n-\t */\n-\tWRITE_ONCE(current-\u003ecapture_control, NULL);\n-\t*capture = READ_ONCE(capc.page);\n-\t/*\n-\t * Technically, it is also possible that compaction is skipped but\n-\t * the page is still captured out of luck(IRQ came and freed the page).\n-\t * Returning COMPACT_SUCCESS in such cases helps in properly accounting\n-\t * the COMPACT[STALL|FAIL] when compaction is skipped.\n-\t */\n-\tif (*capture)\n-\t\tret = COMPACT_SUCCESS;\n-\n-\treturn ret;\n+\treturn compact_zone(\u0026cc, capc);\n }\n \n /**\n@@ -2828,13 +2829,13 @@ static enum compact_result compact_zone_order(struct zone *zone, int order,\n * @alloc_flags: The allocation flags of the current allocation\n * @ac: The context of current allocation\n * @prio: Determines how hard direct compaction should try to succeed\n- * @capture: Pointer to free page created by compaction will be stored here\n+ * @capc: Free page capture bypassing the freelist\n *\n * This is the main entry point for direct page compaction.\n */\n enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,\n \t\tunsigned int alloc_flags, const struct alloc_context *ac,\n-\t\tenum compact_priority prio, struct page **capture)\n+\t\tenum compact_priority prio, struct capture_control *capc)\n {\n \tstruct zoneref *z;\n \tstruct zone *zone;\n@@ -2861,8 +2862,17 @@ enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,\n \t\t\tcontinue;\n \t\t}\n \n+\t\tWRITE_ONCE(capc-\u003ezone, zone);\n+\n \t\tstatus = compact_zone_order(zone, order, gfp_mask, prio,\n-\t\t\t\talloc_flags, ac-\u003ehighest_zoneidx, capture);\n+\t\t\t\talloc_flags, ac-\u003ehighest_zoneidx, capc);\n+\n+\t\tWRITE_ONCE(capc-\u003ezone, NULL);\n+\n+\t\t/* Stop if a page has been captured */\n+\t\tif (READ_ONCE(capc-\u003epage))\n+\t\t\tstatus = COMPACT_SUCCESS;\n+\n \t\trc = max(status, rc);\n \n \t\t/* The allocation should succeed, stop compacting */\ndiff --git a/mm/internal.h b/mm/internal.h\nindex 181e79f1d6a207..5acba3470659d9 100644\n--- a/mm/internal.h\n+++ b/mm/internal.h\n@@ -1059,7 +1059,15 @@ struct compact_control {\n * immediately when one is created during the free path.\n */\n struct capture_control {\n-\tstruct compact_control *cc;\n+\tstruct zone *zone;\n+\tint migratetype;\n+\t/*\n+\t * Allocation request order. May differ from the compaction\n+\t * order: defrag_mode promotes sub-block allocations to\n+\t * pageblock-order compaction; capture still matches at the\n+\t * original allocation order so prep_new_page() is consistent.\n+\t */\n+\tint order;\n \tstruct page *page;\n };\n \ndiff --git a/mm/page_alloc.c b/mm/page_alloc.c\nindex ee902a468c2f5b..f92055827ae958 100644\n--- a/mm/page_alloc.c\n+++ b/mm/page_alloc.c\n@@ -721,14 +721,14 @@ static inline struct capture_control *task_capc(struct zone *zone)\n \treturn unlikely(capc) \u0026\u0026\n \t\t!(current-\u003eflags \u0026 PF_KTHREAD) \u0026\u0026\n \t\t!capc-\u003epage \u0026\u0026\n-\t\tcapc-\u003ecc-\u003ezone == zone ? capc : NULL;\n+\t\tcapc-\u003ezone == zone ? capc : NULL;\n }\n \n static inline bool\n compaction_capture(struct capture_control *capc, struct page *page,\n \t\t int order, int migratetype)\n {\n-\tif (!capc || order != capc-\u003ecc-\u003eorder)\n+\tif (!capc || order != capc-\u003eorder)\n \t\treturn false;\n \n \t/* Do not accidentally pollute CMA or isolated regions*/\n@@ -744,12 +744,12 @@ compaction_capture(struct capture_control *capc, struct page *page,\n \t * have trouble finding a high-order free page.\n \t */\n \tif (order \u003c pageblock_order \u0026\u0026 migratetype == MIGRATE_MOVABLE \u0026\u0026\n-\t capc-\u003ecc-\u003emigratetype != MIGRATE_MOVABLE)\n+\t capc-\u003emigratetype != MIGRATE_MOVABLE)\n \t\treturn false;\n \n-\tif (migratetype != capc-\u003ecc-\u003emigratetype)\n-\t\ttrace_mm_page_alloc_extfrag(page, capc-\u003ecc-\u003eorder, order,\n-\t\t\t\t\t capc-\u003ecc-\u003emigratetype, migratetype);\n+\tif (migratetype != capc-\u003emigratetype)\n+\t\ttrace_mm_page_alloc_extfrag(page, capc-\u003eorder, order,\n+\t\t\t\t\t capc-\u003emigratetype, migratetype);\n \n \tcapc-\u003epage = page;\n \treturn true;\n@@ -4146,18 +4146,67 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,\n \tstruct page *page = NULL;\n \tunsigned long pflags;\n \tunsigned int noreclaim_flag;\n+\tstruct capture_control capc = {\n+\t\t.zone = NULL,\n+\t\t.migratetype = ac-\u003emigratetype,\n+\t\t.order = order,\n+\t\t.page = NULL,\n+\t};\n+\tint compact_order = order;\n \n-\tif (!order)\n+\t/*\n+\t * If fallbacks are not permitted (defrag_mode), we either\n+\t * need to reclaim space in a block of matching type, or clear\n+\t * out an entire block to allow __rmqueue_claim() to convert.\n+\t *\n+\t * Reclaim by itself is primarily freeing space in movable\n+\t * blocks, since that's where the LRU pages live. So this\n+\t * works for movable requests, but not for others.\n+\t *\n+\t * For those, promote the order to help make blocks, instead\n+\t * of spinning in reclaim alone unproductively.\n+\t */\n+\tif ((alloc_flags \u0026 ALLOC_NOFRAGMENT) \u0026\u0026 ac-\u003emigratetype != MIGRATE_MOVABLE)\n+\t\tcompact_order = max(order, pageblock_order);\n+\n+\tif (!compact_order)\n \t\treturn NULL;\n \n \tpsi_memstall_enter(\u0026pflags);\n \tdelayacct_compact_start();\n+\tfs_reclaim_acquire(gfp_mask);\n \tnoreclaim_flag = memalloc_noreclaim_save();\n \n-\t*compact_result = try_to_compact_pages(gfp_mask, order, alloc_flags, ac,\n-\t\t\t\t\t\t\t\tprio, \u0026page);\n+\t/*\n+\t * Make sure the structs are really initialized before we expose the\n+\t * capture control, in case we are interrupted and the interrupt handler\n+\t * frees a page.\n+\t */\n+\tbarrier();\n+\tWRITE_ONCE(current-\u003ecapture_control, \u0026capc);\n+\n+\t*compact_result = try_to_compact_pages(gfp_mask, compact_order,\n+\t\t\t\t\t alloc_flags, ac, prio, \u0026capc);\n+\n+\t/*\n+\t * Make sure we hide capture control first before we read the captured\n+\t * page pointer, otherwise an interrupt could free and capture a page\n+\t * and we would leak it.\n+\t */\n+\tWRITE_ONCE(current-\u003ecapture_control, NULL);\n+\tpage = READ_ONCE(capc.page);\n+\n+\t/*\n+\t * Technically, it is also possible that compaction is skipped but\n+\t * the page is still captured out of luck(IRQ came and freed the page).\n+\t * Returning COMPACT_SUCCESS in such cases helps in properly accounting\n+\t * the COMPACT[STALL|FAIL] when compaction is skipped.\n+\t */\n+\tif (page)\n+\t\t*compact_result = COMPACT_SUCCESS;\n \n \tmemalloc_noreclaim_restore(noreclaim_flag);\n+\tfs_reclaim_release(gfp_mask);\n \tpsi_memstall_leave(\u0026pflags);\n \tdelayacct_compact_end();\n \n@@ -4182,7 +4231,7 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,\n \t\tstruct zone *zone = page_zone(page);\n \n \t\tzone-\u003ecompact_blockskip_flush = false;\n-\t\tcompaction_defer_reset(zone, order, true);\n+\t\tcompaction_defer_reset(zone, compact_order, true);\n \t\tcount_vm_event(COMPACTSUCCESS);\n \t\treturn page;\n \t}\n@@ -4422,9 +4471,14 @@ __alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order,\n \tstruct page *page = NULL;\n \tunsigned long pflags;\n \tbool drained = false;\n+\tint reclaim_order = order;\n+\n+\t/* Match the slowpath compaction promotion in __alloc_pages_direct_compact */\n+\tif ((alloc_flags \u0026 ALLOC_NOFRAGMENT) \u0026\u0026 ac-\u003emigratetype != MIGRATE_MOVABLE)\n+\t\treclaim_order = max(order, pageblock_order);\n \n \tpsi_memstall_enter(\u0026pflags);\n-\t*did_some_progress = __perform_reclaim(gfp_mask, order, ac);\n+\t*did_some_progress = __perform_reclaim(gfp_mask, reclaim_order, ac);\n \tif (unlikely(!(*did_some_progress)))\n \t\tgoto out;\n \n"
} |
| 2/1 | 2026/07/23 16:16 | agent | patch-evaluator |
2mModel:best-expensive Args: null Results: {
"EnableConfigs": [
"COMPACTION"
],
"FocusSymbols": [
"__alloc_pages_direct_compact",
"__alloc_pages_direct_reclaim",
"try_to_compact_pages",
"fast_find_migrateblock",
"suitable_migration_source"
],
"Reasoning": "The patch modifies memory compaction and direct reclaim logic, specifically how `capture_control` is handled and how allocation orders are promoted for non-movable allocations with `ALLOC_NOFRAGMENT`. This is reachable core kernel logic triggered by high-order allocations under memory fragmentation.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Do not list too generic configs (we already have them enabled). Only list those that specifically cover the modified code. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit 71bc7fd1f561b1d61c7a5c7564dcd89d538f8141
Author: syz-cluster <triage@syzkaller.com>
Date: Thu Jul 23 16:16:35 2026 +0000
syz-cluster: applied patch under review
diff --git a/include/linux/compaction.h b/include/linux/compaction.h
index f29ef0653546ed..66a2f70e9e019d 100644
--- a/include/linux/compaction.h
+++ b/include/linux/compaction.h
@@ -58,6 +58,7 @@ enum compact_result {
};
struct alloc_context; /* in mm/internal.h */
+struct capture_control; /* in mm/internal.h */
/*
* Number of free order-0 pages that should be available above given watermark
@@ -92,7 +93,7 @@ extern int fragmentation_index(struct zone *zone, unsigned int order);
extern enum compact_result try_to_compact_pages(gfp_t gfp_mask,
unsigned int order, unsigned int alloc_flags,
const struct alloc_context *ac, enum compact_priority prio,
- struct page **page);
+ struct capture_control *capc);
extern void reset_isolation_suitable(pg_data_t *pgdat);
extern bool compaction_suitable(struct zone *zone, int order,
unsigned long watermark, int highest_zoneidx);
diff --git a/mm/compaction.c b/mm/compaction.c
index f08765ade014ce..977e30b3a2bd16 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -1381,12 +1381,44 @@ static bool suitable_migration_source(struct compact_control *cc,
if (pageblock_skip_persistent(page))
return false;
- if ((cc->mode != MIGRATE_ASYNC) || !cc->direct_compaction)
+ /*
+ * Background compaction produces blocks for the zone at
+ * large, with no particular allocation context. Allow all
+ * block types, including CMA.
+ */
+ if (!cc->direct_compaction)
return true;
block_mt = get_pageblock_migratetype(page);
- if (cc->migratetype == MIGRATE_MOVABLE)
+ /*
+ * CMA pages can only be taken by ALLOC_CMA requests. For anybody
+ * else, vacating a CMA block consumes free pages the caller
+ * could have used, and produces free pages it cannot.
+ */
+ if (is_migrate_cma(block_mt) && !(cc->alloc_flags & ALLOC_CMA))
+ return false;
+
+ /*
+ * Per default, scans are restricted to blocks compatible with
+ * the request, to prevent cross-contamination. Once
+ * compaction priority escalates to synchronous scans, though,
+ * scan all blocks to try to make forward progress. For
+ * movable request, this likely helps little: there shouldn't
+ * be many migratable pages inside non-movable blocks besides
+ * allocator fallbacks. For non-movable requests, this helps a
+ * lot, as they can finally scan movable blocks.
+ */
+ if (cc->mode != MIGRATE_ASYNC)
+ return true;
+
+ /*
+ * Prevent <pageblock_order unmovable/reclaimable requests from
+ * polluting movable blocks through fallbacks. Whole-block production
+ * (directly requested, or defrag_mode) is exempt as the allocator
+ * claims and converts these.
+ */
+ if (cc->migratetype == MIGRATE_MOVABLE || cc->order >= pageblock_order)
return is_migrate_movable(block_mt);
else
return block_mt == cc->migratetype;
@@ -1974,12 +2006,12 @@ static unsigned long fast_find_migrateblock(struct compact_control *cc)
return pfn;
/*
- * Only allow kcompactd and direct requests for movable pages to
- * quickly clear out a MOVABLE pageblock for allocation. This
- * reduces the risk that a large movable pageblock is freed for
- * an unmovable/reclaimable small allocation.
+ * Prevent <pageblock_order unmovable/reclaimable requests from
+ * polluting movable blocks through fallbacks. Whole-block production
+ * is exempt as the allocator claims and converts these.
*/
- if (cc->direct_compaction && cc->migratetype != MIGRATE_MOVABLE)
+ if (cc->direct_compaction && cc->migratetype != MIGRATE_MOVABLE &&
+ cc->order < pageblock_order)
return pfn;
/*
@@ -2770,9 +2802,8 @@ compact_zone(struct compact_control *cc, struct capture_control *capc)
static enum compact_result compact_zone_order(struct zone *zone, int order,
gfp_t gfp_mask, enum compact_priority prio,
unsigned int alloc_flags, int highest_zoneidx,
- struct page **capture)
+ struct capture_control *capc)
{
- enum compact_result ret;
struct compact_control cc = {
.order = order,
.search_order = order,
@@ -2787,38 +2818,8 @@ static enum compact_result compact_zone_order(struct zone *zone, int order,
.ignore_skip_hint = (prio == MIN_COMPACT_PRIORITY),
.ignore_block_suitable = (prio == MIN_COMPACT_PRIORITY)
};
- struct capture_control capc = {
- .cc = &cc,
- .page = NULL,
- };
- /*
- * Make sure the structs are really initialized before we expose the
- * capture control, in case we are interrupted and the interrupt handler
- * frees a page.
- */
- barrier();
- WRITE_ONCE(current->capture_control, &capc);
-
- ret = compact_zone(&cc, &capc);
-
- /*
- * Make sure we hide capture control first before we read the captured
- * page pointer, otherwise an interrupt could free and capture a page
- * and we would leak it.
- */
- WRITE_ONCE(current->capture_control, NULL);
- *capture = READ_ONCE(capc.page);
- /*
- * Technically, it is also possible that compaction is skipped but
- * the page is still captured out of luck(IRQ came and freed the page).
- * Returning COMPACT_SUCCESS in such cases helps in properly accounting
- * the COMPACT[STALL|FAIL] when compaction is skipped.
- */
- if (*capture)
- ret = COMPACT_SUCCESS;
-
- return ret;
+ return compact_zone(&cc, capc);
}
/**
@@ -2828,13 +2829,13 @@ static enum compact_result compact_zone_order(struct zone *zone, int order,
* @alloc_flags: The allocation flags of the current allocation
* @ac: The context of current allocation
* @prio: Determines how hard direct compaction should try to succeed
- * @capture: Pointer to free page created by compaction will be stored here
+ * @capc: Free page capture bypassing the freelist
*
* This is the main entry point for direct page compaction.
*/
enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
unsigned int alloc_flags, const struct alloc_context *ac,
- enum compact_priority prio, struct page **capture)
+ enum compact_priority prio, struct capture_control *capc)
{
struct zoneref *z;
struct zone *zone;
@@ -2861,8 +2862,17 @@ enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
continue;
}
+ WRITE_ONCE(capc->zone, zone);
+
status = compact_zone_order(zone, order, gfp_mask, prio,
- alloc_flags, ac->highest_zoneidx, capture);
+ alloc_flags, ac->highest_zoneidx, capc);
+
+ WRITE_ONCE(capc->zone, NULL);
+
+ /* Stop if a page has been captured */
+ if (READ_ONCE(capc->page))
+ status = COMPACT_SUCCESS;
+
rc = max(status, rc);
/* The allocation should succeed, stop compacting */
diff --git a/mm/internal.h b/mm/internal.h
index 181e79f1d6a207..5acba3470659d9 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -1059,7 +1059,15 @@ struct compact_control {
* immediately when one is created during the free path.
*/
struct capture_control {
- struct compact_control *cc;
+ struct zone *zone;
+ int migratetype;
+ /*
+ * Allocation request order. May differ from the compaction
+ * order: defrag_mode promotes sub-block allocations to
+ * pageblock-order compaction; capture still matches at the
+ * original allocation order so prep_new_page() is consistent.
+ */
+ int order;
struct page *page;
};
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index ee902a468c2f5b..f92055827ae958 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -721,14 +721,14 @@ static inline struct capture_control *task_capc(struct zone *zone)
return unlikely(capc) &&
!(current->flags & PF_KTHREAD) &&
!capc->page &&
- capc->cc->zone == zone ? capc : NULL;
+ capc->zone == zone ? capc : NULL;
}
static inline bool
compaction_capture(struct capture_control *capc, struct page *page,
int order, int migratetype)
{
- if (!capc || order != capc->cc->order)
+ if (!capc || order != capc->order)
return false;
/* Do not accidentally pollute CMA or isolated regions*/
@@ -744,12 +744,12 @@ compaction_capture(struct capture_control *capc, struct page *page,
* have trouble finding a high-order free page.
*/
if (order < pageblock_order && migratetype == MIGRATE_MOVABLE &&
- capc->cc->migratetype != MIGRATE_MOVABLE)
+ capc->migratetype != MIGRATE_MOVABLE)
return false;
- if (migratetype != capc->cc->migratetype)
- trace_mm_page_alloc_extfrag(page, capc->cc->order, order,
- capc->cc->migratetype, migratetype);
+ if (migratetype != capc->migratetype)
+ trace_mm_page_alloc_extfrag(page, capc->order, order,
+ capc->migratetype, migratetype);
capc->page = page;
return true;
@@ -4146,18 +4146,67 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
struct page *page = NULL;
unsigned long pflags;
unsigned int noreclaim_flag;
+ struct capture_control capc = {
+ .zone = NULL,
+ .migratetype = ac->migratetype,
+ .order = order,
+ .page = NULL,
+ };
+ int compact_order = order;
- if (!order)
+ /*
+ * If fallbacks are not permitted (defrag_mode), we either
+ * need to reclaim space in a block of matching type, or clear
+ * out an entire block to allow __rmqueue_claim() to convert.
+ *
+ * Reclaim by itself is primarily freeing space in movable
+ * blocks, since that's where the LRU pages live. So this
+ * works for movable requests, but not for others.
+ *
+ * For those, promote the order to help make blocks, instead
+ * of spinning in reclaim alone unproductively.
+ */
+ if ((alloc_flags & ALLOC_NOFRAGMENT) && ac->migratetype != MIGRATE_MOVABLE)
+ compact_order = max(order, pageblock_order);
+
+ if (!compact_order)
return NULL;
psi_memstall_enter(&pflags);
delayacct_compact_start();
+ fs_reclaim_acquire(gfp_mask);
noreclaim_flag = memalloc_noreclaim_save();
- *compact_result = try_to_compact_pages(gfp_mask, order, alloc_flags, ac,
- prio, &page);
+ /*
+ * Make sure the structs are really initialized before we expose the
+ * capture control, in case we are interrupted and the interrupt handler
+ * frees a page.
+ */
+ barrier();
+ WRITE_ONCE(current->capture_control, &capc);
+
+ *compact_result = try_to_compact_pages(gfp_mask, compact_order,
+ alloc_flags, ac, prio, &capc);
+
+ /*
+ * Make sure we hide capture control first before we read the captured
+ * page pointer, otherwise an interrupt could free and capture a page
+ * and we would leak it.
+ */
+ WRITE_ONCE(current->capture_control, NULL);
+ page = READ_ONCE(capc.page);
+
+ /*
+ * Technically, it is also possible that compaction is skipped but
+ * the page is still captured out of luck(IRQ came and freed the page).
+ * Returning COMPACT_SUCCESS in such cases helps in properly accounting
+ * the COMPACT[STALL|FAIL] when compaction is skipped.
+ */
+ if (page)
+ *compact_result = COMPACT_SUCCESS;
memalloc_noreclaim_restore(noreclaim_flag);
+ fs_reclaim_release(gfp_mask);
psi_memstall_leave(&pflags);
delayacct_compact_end();
@@ -4182,7 +4231,7 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
struct zone *zone = page_zone(page);
zone->compact_blockskip_flush = false;
- compaction_defer_reset(zone, order, true);
+ compaction_defer_reset(zone, compact_order, true);
count_vm_event(COMPACTSUCCESS);
return page;
}
@@ -4422,9 +4471,14 @@ __alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order,
struct page *page = NULL;
unsigned long pflags;
bool drained = false;
+ int reclaim_order = order;
+
+ /* Match the slowpath compaction promotion in __alloc_pages_direct_compact */
+ if ((alloc_flags & ALLOC_NOFRAGMENT) && ac->migratetype != MIGRATE_MOVABLE)
+ reclaim_order = max(order, pageblock_order);
psi_memstall_enter(&pflags);
- *did_some_progress = __perform_reclaim(gfp_mask, order, ac);
+ *did_some_progress = __perform_reclaim(gfp_mask, reclaim_order, ac);
if (unlikely(!(*did_some_progress)))
goto out;
|
| 3/2 | 2026/07/23 16:16 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 5772 output: 27 thoughts: 364 Thoughts: **Analyzing the Memory Compaction Patch** Okay, so I've got this patch that's tweaking the memory compaction subsystem. Right away, I see it touches some key files: `mm/compaction.c`, `mm/page_alloc.c`, `include/linux/compaction.h`, and `mm/internal.h`. It looks like we're changing how `capture_control` is managed during direct compaction and are also re-writing some logic that determines migration sources and targets, specifically around handling `ALLOC_NOFRAGMENT` flags and the `pageblock_order`. My immediate thought is, "Okay, we're optimizing fragmentation handling for specific allocation types during compaction and direct reclaim." This is important because the changes are about promoting the order to `pageblock_order` for non-movable allocations with `ALLOC_NOFRAGMENT` flags during direct compaction and direct reclaim My first check is always reachability and functionality. Memory compaction is absolutely a core feature, triggered when high-order allocations hit fragmentation walls. This isn't some niche corner case; it's a critical part of how the kernel manages memory pressure. The patch is probably reachable. Now, my mind jumps to fuzzing targets. Let's see... the patch impacts these functions, and these are the critical bits of logic I need to focus on: - `suitable_migration_source` - `fast_find_migrateblock` - `compact_zone_order` - `try_to_compact_pages` - `compaction_capture` - `__alloc_pages_direct_compact` - `__alloc_pages_direct_reclaim` Looks like `__alloc_pages_direct_compact` and `__alloc_pages_direct_reclaim` are part of the page allocator slowpath. `try_to_compact_pages` is the entry point for direct compaction. `suitable_migration_source` and `fast_find_migrateblock` are used during the actual compaction. Finally, are there any configuration dependencies I need to be aware of? Compaction, thankfully, is controlled by `CONFIG_COMPACTION`. Let's verify that quickly in `mm/Kconfig` to be sure. That'll be a key pre-requisite for testing. |
| 4/2 | 2026/07/23 16:16 | tool | grepper |
0mArgs:{
"Expression": "config COMPACTION",
"PathPrefix": "mm/Kconfig"
}Results: {
"Output": "mm/Kconfig=642=config BALLOON_MIGRATION\n--\nmm/Kconfig-653-# support for memory compaction\nmm/Kconfig:654:config COMPACTION\nmm/Kconfig-655-\tbool \"Allow for memory compaction\"\n"
} |
| 5/2 | 2026/07/23 16:16 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 6733 output: 37 thoughts: 101 Thoughts: **Analyzing Configuration Dependencies for Memory Compaction** Okay, so I'm looking at this code and need to determine the essential configuration options. First, the obvious: I need to verify if `CONFIG_COMPACTION` is enabled, as that's clearly the primary switch for the entire compaction mechanism. And since compaction frequently involves moving pages around, I should double-check that `CONFIG_MIGRATION` is also enabled, as migration is typically a critical part of the process. Now, let's cast a wider net. I'll take a quick look to see if there are *any* other config dependencies. The patch touches both `mm/compaction.c` and `mm/page_alloc.c`. I'll cross-reference those files and the configuration options. Right away, I know `mm/compaction.c` is going to be compiled only if `CONFIG_COMPACTION` is defined, which reinforces the initial assumption. Based on this, I would guess this patch depends solely on `CONFIG_COMPACTION` and `CONFIG_MIGRATION`, with `CONFIG_COMPACTION` being essential for this code path. |
| 6/2 | 2026/07/23 16:16 | tool | grepper |
0mError:no matches Args: {
"Expression": "obj-\\$\\(CONFIG_COMPACTION\\).*compaction\\.o",
"PathPrefix": "mm/Makefile"
}Results: {
"error": "no matches"
} |
| 7/2 | 2026/07/23 16:16 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7125 output: 27 thoughts: 12 Thoughts: Okay, let's dive into it. Here's how I'd approach this, thinking as an expert: **Compaction in `mm/Makefile` – Quick Check** Right, before I get too deep into this specific issue, my first instinct is to see how the compaction process is being handled at a fundamental level. I want to quickly understand the build system's configuration. So, my mind immediately jumps to `mm/Makefile`. That's where I'd expect to find the directives controlling how the memory management components are compiled and linked, and by extension, any compaction routines or related logic. A quick scan there can often reveal if compaction is even enabled by default or if there are specific compile-time flags I need to consider. This is a crucial first step; I'm not going to spin my wheels digging through source code if the Makefile isn't even configured to include the parts that I need to analyze. Gotta establish my baseline, know what tools the build uses. |
| 8/2 | 2026/07/23 16:17 | tool | grepper |
0mArgs:{
"Expression": "compaction\\.o",
"PathPrefix": "mm/Makefile"
}Results: {
"Output": "mm/Makefile=51=obj-y\t\t\t:= filemap.o mempool.o oom_kill.o fadvise.o \\\n--\nmm/Makefile-55-\t\t\t mm_init.o percpu.o slab_common.o \\\nmm/Makefile:56:\t\t\t compaction.o show_mem.o \\\nmm/Makefile-57-\t\t\t interval_tree.o list_lru.o workingset.o \\\n"
} |
| 9/2 | 2026/07/23 16:17 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7488 output: 30 thoughts: 34 Thoughts: Okay, here's my interpretation of those thoughts, tailored for an expert audience, presented in the first person: **Investigating Compaction's Compilation** Alright, so I'm thinking about `compaction.o`. Is it *always* built into the kernel, or is it conditional? The immediate question in my mind is: what are the build options at play? It's a key question when thinking about performance and memory management overhead. The reflex is to go straight to `mm/compaction.c`. I need to confirm whether `CONFIG_COMPACTION` is used with a `#ifdef` or similar conditional compilation structure. That’s the quickest way to determine if compaction is built-in or if it's dependent on a specific kernel configuration option. This will directly dictate whether it's always part of my kernel or something I can enable or disable. |
| 10/2 | 2026/07/23 16:18 | tool | grepper |
0mArgs:{
"Expression": "CONFIG_COMPACTION",
"PathPrefix": "mm/compaction.c"
}Results: {
"Output": "mm/compaction.c-28-\nmm/compaction.c:29:#ifdef CONFIG_COMPACTION\nmm/compaction.c-30-/*\n--\nmm/compaction.c=59=static inline bool is_via_compact_memory(int order) { return false; }\n--\nmm/compaction.c-61-\nmm/compaction.c:62:#if defined CONFIG_COMPACTION || defined CONFIG_CMA\nmm/compaction.c-63-\n--\nmm/compaction.c=91=static unsigned long release_free_list(struct list_head *freepages)\n--\nmm/compaction.c-115-\nmm/compaction.c:116:#ifdef CONFIG_COMPACTION\nmm/compaction.c-117-\n--\nmm/compaction.c=490=static bool test_and_set_skip(struct compact_control *cc, struct page *page)\n--\nmm/compaction.c-493-}\nmm/compaction.c:494:#endif /* CONFIG_COMPACTION */\nmm/compaction.c-495-\n--\nmm/compaction.c=1337=isolate_migratepages_range(struct compact_control *cc, unsigned long start_pfn,\n--\nmm/compaction.c-1372-\nmm/compaction.c:1373:#endif /* CONFIG_COMPACTION || CONFIG_CMA */\nmm/compaction.c:1374:#ifdef CONFIG_COMPACTION\nmm/compaction.c-1375-\n--\nmm/compaction.c=3363=subsys_initcall(kcompactd_init)\nmm/compaction.c-3364-\nmm/compaction.c:3365:#endif /* CONFIG_COMPACTION */\n"
} |
| 11/2 | 2026/07/23 16:18 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 8187 output: 31 thoughts: 175 Thoughts: **Focussing Fuzzing Efforts for Memory Compaction** Alright, so the key area to target here is definitely `CONFIG_COMPACTION`. That's where the heart of the matter lies. Now, to make the most of fuzzing, I need to pinpoint the functions that are most likely to reveal vulnerabilities. Let's see... I've got a list here: `__alloc_pages_direct_compact`, `__alloc_pages_direct_reclaim`, `try_to_compact_pages`, `compact_zone_order`, `compaction_capture`, `fast_find_migrateblock`, and `suitable_migration_source`. `__alloc_pages_direct_compact` and `__alloc_pages_direct_reclaim` look like strong candidates to start with. They're right there, dealing with allocation and reclaiming, which is often where subtle issues arise. `try_to_compact_pages` also seems promising, it's the point where the actual work happens. Now, `compaction_capture`... hmm, I recall it being related to `task_capc`, which in turn gets called from `get_page_from_freelist` or something similar, right? Time to dig into `compaction_capture` a bit deeper, see how that fits into the broader picture. Gotta understand its interaction. |
| 12/2 | 2026/07/23 16:18 | tool | grepper |
0mArgs:{
"Expression": "compaction_capture",
"PathPrefix": "mm/page_alloc.c"
}Results: {
"Output": "mm/page_alloc.c=727=static inline bool\nmm/page_alloc.c:728:compaction_capture(struct capture_control *capc, struct page *page,\nmm/page_alloc.c-729-\t\t int order, int migratetype)\n--\nmm/page_alloc.c=764=static inline bool\nmm/page_alloc.c:765:compaction_capture(struct capture_control *capc, struct page *page,\nmm/page_alloc.c-766-\t\t int order, int migratetype)\n--\nmm/page_alloc.c=936=static inline void __free_one_page(struct page *page,\n--\nmm/page_alloc.c-958-\nmm/page_alloc.c:959:\t\tif (compaction_capture(capc, page, order, migratetype)) {\nmm/page_alloc.c-960-\t\t\taccount_freepages(zone, -(1 \u003c\u003c order), migratetype);\n"
} |
| 13/2 | 2026/07/23 16:18 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 8944 output: 35 thoughts: 140 Thoughts: **Analyzing Memory Allocation Hotspots** Okay, so I'm digging into memory allocation performance, and it's clear that `__free_one_page` is a serious bottleneck – a real hot path. We need to tread carefully around anything that might interact with it too frequently. Considering that, I'm thinking we should steer clear of focusing on `compaction_capture` as a critical function for optimization right now; it could be too intertwined with `__free_one_page` and exacerbate any issues. On the other hand, `__alloc_pages_direct_compact` and `__alloc_pages_direct_reclaim` present a different opportunity. These are known as slower allocation paths. This makes them good candidates. We also have `try_to_compact_pages` which is another slow path, by definition. Similarly, `fast_find_migrateblock` and `suitable_migration_source` are part of the compaction process, a relatively slow area compared to the standard alloc/free operations. Given the options, let's drill down into `__alloc_pages_direct_compact` and `__alloc_pages_direct_reclaim`. They're probably where we can get the most significant gains by optimizing. |
| 14/2 | 2026/07/23 16:18 | tool | grepper |
0mArgs:{
"Expression": "__alloc_pages_direct_compact",
"PathPrefix": "mm/page_alloc.c"
}Results: {
"Output": "mm/page_alloc.c=4141=static struct page *\nmm/page_alloc.c:4142:__alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,\nmm/page_alloc.c-4143-\t\tunsigned int alloc_flags, const struct alloc_context *ac,\n--\nmm/page_alloc.c=4318=static inline struct page *\nmm/page_alloc.c:4319:__alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,\nmm/page_alloc.c-4320-\t\tunsigned int alloc_flags, const struct alloc_context *ac,\n--\nmm/page_alloc.c=4467=__alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order,\n--\nmm/page_alloc.c-4475-\nmm/page_alloc.c:4476:\t/* Match the slowpath compaction promotion in __alloc_pages_direct_compact */\nmm/page_alloc.c-4477-\tif ((alloc_flags \u0026 ALLOC_NOFRAGMENT) \u0026\u0026 ac-\u003emigratetype != MIGRATE_MOVABLE)\n--\nmm/page_alloc.c=4779=__alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,\n--\nmm/page_alloc.c-4936-\t/* Try direct compaction and then allocating */\nmm/page_alloc.c:4937:\tpage = __alloc_pages_direct_compact(gfp_mask, order, alloc_flags, ac,\nmm/page_alloc.c-4938-\t\t\t\t\tcompact_priority, \u0026compact_result);\n"
} |
| 15/2 | 2026/07/23 16:18 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 9814 output: 138 thoughts: 481 Thoughts: **My Analysis of the Memory Compaction Patch** Okay, so I've been reviewing this patch and I'm honing in on the key areas. Initially, my thought process zeroes in on a few crucial functions: `__alloc_pages_direct_compact`, `__alloc_pages_direct_reclaim`, `try_to_compact_pages`, `fast_find_migrateblock`, and `suitable_migration_source`. These seem to be the core components involved in the compaction and direct reclaim process. My immediate question is about dependencies – is `CONFIG_COMPACTION` the only configuration needed to enable this functionality? A quick check confirms that, yes, `CONFIG_COMPACTION` is the primary enabler. Good. No other critical config options besides `ALLOC_NOFRAGMENT` (which is a flag) and `MIGRATE_MOVABLE`, which seems to be a migratetype. Now, let's nail down the specific modifications. It seems `__alloc_pages_direct_reclaim` gets tweaked to influence the allocation order for non-movable allocations using `ALLOC_NOFRAGMENT`. Also, `__alloc_pages_direct_compact` sees a modification, order promotion and the proper use of `capture_control`. Additionally, `try_to_compact_pages` shifts from taking `page **` to taking `capture_control`. Next, I need to know the scope of these functions, so I check if they are static. As I expected, `__alloc_pages_direct_compact`, `__alloc_pages_direct_reclaim`, `fast_find_migrateblock` and `suitable_migration_source` are static, while `try_to_compact_pages` is non-static or exported. So, for the fuzzer, these functions are the obvious targets. I know this code handles high-order allocations, potentially under fragmented memory conditions. Just to be thorough, I double-check that `COMPACTION` is indeed sufficient. And yes, it is. Time to `set-results`. |
| 16/2 | 2026/07/23 16:18 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"COMPACTION"
],
"FocusSymbols": [
"__alloc_pages_direct_compact",
"__alloc_pages_direct_reclaim",
"try_to_compact_pages",
"fast_find_migrateblock",
"suitable_migration_source"
],
"Reasoning": "The patch modifies memory compaction and direct reclaim logic, specifically how `capture_control` is handled and how allocation orders are promoted for non-movable allocations with `ALLOC_NOFRAGMENT`. This is reachable core kernel logic triggered by high-order allocations under memory fragmentation.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"COMPACTION"
],
"FocusSymbols": [
"__alloc_pages_direct_compact",
"__alloc_pages_direct_reclaim",
"try_to_compact_pages",
"fast_find_migrateblock",
"suitable_migration_source"
],
"Reasoning": "The patch modifies memory compaction and direct reclaim logic, specifically how `capture_control` is handled and how allocation orders are promoted for non-movable allocations with `ALLOC_NOFRAGMENT`. This is reachable core kernel logic triggered by high-order allocations under memory fragmentation.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|