Re: [PATCH v4 07/14] mm/mglru: don't abort scan immediately right after aging

From: Chen Ridong

Date: Wed Apr 08 2026 - 05:35:43 EST




On 2026/4/7 19:57, Kairui Song via B4 Relay wrote:
> From: Kairui Song <kasong@xxxxxxxxxxx>
>
> Right now, if eviction triggers aging, the reclaimer will abort. This is
> not the optimal strategy for several reasons.
>
> Aborting the reclaim early wastes a reclaim cycle when under pressure,
> and for concurrent reclaim, if the LRU is under aging, all concurrent
> reclaimers might fail. And if the age has just finished, new cold folios
> exposed by the aging are not reclaimed until the next reclaim iteration.
>
> What's more, the current aging trigger is quite lenient, having 3 gens
> with a reclaim priority lower than default will trigger aging, and
> blocks reclaiming from one memcg. This wastes reclaim retry cycles
> easily. And in the worst case, if the reclaim is making slower progress
> and all following attempts fail due to being blocked by aging, it
> triggers unexpected early OOM.
>
> And if a lruvec requires aging, it doesn't mean it's hot. Instead, the
> lruvec could be idle for quite a while, and hence it might contain lots
> of cold folios to be reclaimed.
>
> While it's helpful to rotate memcg LRU after aging for global reclaim,
> as global reclaim fairness is coupled with the rotation in shrink_many,
> memcg fairness is instead handled by cgroup iteration in
> shrink_node_memcgs. So, for memcg level pressure, this abort is not the
> key part for keeping the fairness. And in most cases, there is no need
> to age, and fairness must be achieved by upper-level reclaim control.
>
> So instead, just keep the scanning going unless one whole batch of
> folios failed to be isolated or enough folios have been scanned, which
> is triggered by evict_folios returning 0. And only abort for global
> reclaim after one batch, so when there are fewer memcgs, progress is
> still made, and the fairness mechanism described above still works fine.
>
> And in most cases, the one more batch attempt for global reclaim might
> just be enough to satisfy what the reclaimer needs, hence improving
> global reclaim performance by reducing reclaim retry cycles.
>
> Rotation is still there after the reclaim is done, which still follows
> the comment in mmzone.h. And fairness still looking good.
>
> Reviewed-by: Axel Rasmussen <axelrasmussen@xxxxxxxxxx>
> Signed-off-by: Kairui Song <kasong@xxxxxxxxxxx>
> ---
> mm/vmscan.c | 8 ++++++--
> 1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index c673830f4ba8..354c6fef3c42 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -4979,7 +4979,7 @@ static bool should_abort_scan(struct lruvec *lruvec, struct scan_control *sc)
> */
> static bool try_to_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
> {
> - bool need_rotate = false;
> + bool need_rotate = false, should_age = false;
> long nr_batch, nr_to_scan;
> int swappiness = get_swappiness(lruvec, sc);
> struct mem_cgroup *memcg = lruvec_memcg(lruvec);
> @@ -5000,7 +5000,7 @@ static bool try_to_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
> if (should_run_aging(lruvec, max_seq, sc, swappiness)) {
> if (try_to_inc_max_seq(lruvec, max_seq, swappiness, false))
> need_rotate = true;
> - break;
> + should_age = true;
> }
>
> nr_batch = min(nr_to_scan, MIN_LRU_BATCH);
> @@ -5011,6 +5011,10 @@ static bool try_to_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
> if (should_abort_scan(lruvec, sc))
> break;
>
> + /* For cgroup reclaim, fairness is handled by iterator, not rotation */
> + if (root_reclaim(sc) && should_age)
> + break;
> +
> nr_to_scan -= delta;
> cond_resched();
> }
>

Reviewed-by: Chen Ridong <chenridong@xxxxxxxxxxxxxxx>

--
Best regards,
Ridong