Tainted SPBs reserve headroom (per spb_tainted_reserve()) so the allocator can satisfy non-movable allocations without tainting fresh clean SPBs. Compaction's free-page scanner can erode that reserve by picking destination pages from tainted-SPB free lists -- exactly the headroom we need for unmovable demand. Refuse tainted-SPB pageblocks as compaction destinations once nr_free is at or below spb_tainted_reserve(sb). Clean SPBs (no reserve) stay fully eligible. This naturally biases compaction toward producing free pageblocks inside clean SPBs, where they're useful for hugepage allocation. Combined with the source-side skip and the kcompactd wake fix, this is sufficient for kcompactd to handle clean-SPB consolidation alone. Signed-off-by: Rik van Riel Assisted-by: Claude:claude-opus-4.7 syzkaller --- mm/compaction.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/mm/compaction.c b/mm/compaction.c index f9de52875c88..3d1015dffa82 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -1503,6 +1503,21 @@ static bool suitable_migration_target(struct compact_control *cc, if (cc->ignore_block_suitable) return true; + /* + * Tainted superpageblocks reserve some headroom for non-movable + * allocations. Don't spill compaction migration into that reserve -- + * doing so erodes the headroom the allocator was holding to avoid + * tainting fresh clean SPBs. Clean SPBs (no reserve) stay eligible. + */ + if (cc->zone->nr_superpageblocks) { + struct superpageblock *sb = + pfn_to_superpageblock(cc->zone, page_to_pfn(page)); + + if (sb && spb_get_category(sb) == SB_TAINTED && + sb->nr_free <= spb_tainted_reserve(sb)) + return false; + } + /* If the block is MIGRATE_MOVABLE or MIGRATE_CMA, allow migration */ if (is_migrate_movable(get_pageblock_migratetype(page))) return true; -- 2.54.0