Re: [PATCH mm-new v2] mm: vmscan: put rotation-missed folios at the LRU tail
From: Barry Song
Date: Mon Sep 21 2026 - 03:07:43 EST
On Sun, Sep 20, 2026 at 9:25 PM Ridong Chen <ridong.chen@xxxxxxxxx> wrote:
>
> From: Ridong Chen <chenridong@xxxxxxxxxx>
>
> The page reclaim isolates a batch of folios from the tail of an LRU list
> and works on them one by one. For a suitable swap-backed folio on an
> async swap device, it queues the folio for writeback and, after finishing
> the batch, puts the folio back to the head of the original LRU list.
>
> Meanwhile the page writeback flushes the queued folios in its own,
> independent batches. For each folio it writes back it calls
> folio_rotate_reclaimable(), which tries to rotate the folio to the LRU
> tail. But folio_rotate_reclaimable() only takes effect once the folio has
> been put back by reclaim. If the async swap device is fast enough, the
> writeback can complete a folio while reclaim is still working on the rest
> of the batch that contains it. In that case the folio stays near the head
> and reclaim will not revisit it before wrapping around, causing a cold/hot
> inversion: a clean, written-back folio that should be a prime reclaim
> candidate is kept ahead of hotter folios.
>
> commit 359a5e1416ca ("mm: multi-gen LRU: retry folios written back while
> isolated") addressed this for MGLRU only. The traditional active/inactive
> LRU has the same problem, reported at [1]. A reproducer is available at
> [2].
>
> Rather than re-reclaiming those folios (which would drop the swap cache
> that may still be useful for a future hit [4]), restore the rotation that
> was missed: when move_folios_to_lru() puts a folio back, add it to the LRU
> tail if it looks like it missed folio_rotate_reclaimable() (inactive, not
> mapped, not dirty and not under writeback). A referenced folio is left at
> the head so it still gets a second chance, and a folio with an unexpected
> reference (e.g. a GUP or speculative pin) is left at the head because it
> cannot be reclaimed yet anyway. A new do_rotate parameter gates this so
> it only applies on the reclaim put-back path (shrink_inactive_list()), not
> on shrink_active_list() where the list order is already deliberate. This
> approach was suggested by Barry Song [3].
>
> Only the traditional LRU is handled here. MGLRU already retries such
> folios via its own clean-list retry pass in evict_folios(), so it is left
> unchanged. The same do_rotate scheme could later replace that retry pass
> to unify both LRUs, which is left for a follow-up.
>
> Test result with [2]:
>
> Without patch:
> cat memory.usage_in_bytes
> 1073700864
> cat memory.memsw.usage_in_bytes
> 1413124096
>
> free -h
> total used free
> Mem: 1.6Gi 1.2Gi 299Mi
> Swap: 1.0Gi 678Mi 346Mi
>
> With patch:
> cat memory.usage_in_bytes
> 1071140864
> cat memory.memsw.usage_in_bytes
> 1413423104
>
> free -h
> total used free
> Mem: 1.6Gi 1.2Gi 322Mi
> Swap: 1.0Gi 328Mi 695Mi
>
> After applying the patch, the difference between
> memory.memsw.usage_in_bytes and memory.usage_in_bytes is close to the swap
> "used" value reported by 'free -h'.
>
> [1] https://lore.kernel.org/linux-kernel/20241010081802.290893-1-chenridong@xxxxxxxxxxxxxxx/
> [2] https://lore.kernel.org/lkml/46037a37-4cf6-448e-a94b-30a4d16e8814@xxxxxxxxx/
> [3] https://lore.kernel.org/lkml/CAGsJ_4zwP3_+EYY5Ug9EJ+yD1UdxsBSGr25u8s1K3u_i7LH3Zg@xxxxxxxxxxxxxx/
> [4] https://lore.kernel.org/linux-mm/20260911121341.178028-1-alex@xxxxxxxx/
>
> Suggested-by: Barry Song <baohua@xxxxxxxxxx>
> Signed-off-by: Ridong Chen <chenridong@xxxxxxxxxx>
> ---
LGTM,
Reviewed-by: Barry Song <baohua@xxxxxxxxxx>