Re: [PATCH 2/4] mm: compaction: support non-movable compaction for pageblock requests

From: Vlastimil Babka (SUSE)

Date: Wed Jul 01 2026 - 10:25:15 EST


On 6/26/26 20:21, Johannes Weiner wrote:
> While trying to fix a reclaim storm in defrag_mode, I noticed that
> non-movable direct compaction is extremely inefficient.
>
> When searching for space to evacuate, compaction only allows blocks of
> the same type as the incoming request. This is to prevent migratetype
> pollution, where a small non-movable request frees space in a movable
> block and provokes the allocator to fall back and pollute it.
>
> This protection is reasonable on one hand, but the downside is that it
> makes non-movable direct compaction nearly useless: if we get the type
> annotations right, by definition there aren't any movable pages inside
> the non-movable blocks it is allowed to scan.
>
> With defrag_mode, the goal is the production of whole blocks, which
> are essentially type neutral: __rmqueue_claim() will convert them
> wholesale on alloc. This makes type mixing and pollution a non-issue.
>
> Fix the pollution gates to take the requested order into account, and
> allow whole-block requests to scan blocks of other types.
>
> The only exception is CMA blocks. That type is sticky and these blocks
> cannot be claimed to other types. Continue to be strict with them, and
> allow only explicit ALLOC_CMA requests and kcompactd to evacuate them.
>
> Signed-off-by: Johannes Weiner <hannes@xxxxxxxxxxx>

Reviewed-by: Vlastimil Babka (SUSE) <vbabka@xxxxxxxxxx>

A suggestion:

> ---
> mm/compaction.c | 35 ++++++++++++++++++++++++++++-------
> 1 file changed, 28 insertions(+), 7 deletions(-)
>
> diff --git a/mm/compaction.c b/mm/compaction.c
> index f08765ade014..7df3a85d43af 100644
> --- a/mm/compaction.c
> +++ b/mm/compaction.c
> @@ -1381,12 +1381,33 @@ 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;
> +
> + if (cc->mode != MIGRATE_ASYNC)
> + return true;

This now stands out as uncommented. Can we come up with a rationale? :)

> +
> + /*
> + * Prevent small unmovable/reclaimable requests from polluting
> + * movable blocks through fallbacks. Whole-block production 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 +1995,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 small 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;
>
> /*