Re: [PATCH] mm: madvise: drop MADV_PAGEOUT folios at swap writeback completion
From: Barry Song
Date: Mon Sep 21 2026 - 17:58:14 EST
On Mon, Sep 21, 2026 at 11:37 PM David Hildenbrand (Arm)
<david@xxxxxxxxxx> wrote:
>
> On 9/21/26 17:24, Alexandre Ghiti wrote:
> > On an asynchronous swap device MADV_PAGEOUT only marks the folio
> > PG_reclaim and rotates it to the tail of the inactive list once its
> > writeback completes, so the memory is not actually freed until a later
> > reclaim scan removes the by then clean swap cache folio.
> But we have the same behavior when just reclaiming memory ordinarily? It's added
> to the swapcache and only the next scan actually frees up the memory.
>
> Wouldn't we memory we reclaim ... just gone, like in the sync case?
For synchronous I/O, such as zswap and zram, the memory is released
immediately after sync I/O is done.
For asynchronous I/O, such as NVMe, the swapcache is currently
expected to be rotated back to the tail of the LRU and wait for
another scan. Alexandre once mentioned that when he tried handling
async I/O the same way as sync I/O—releasing the memory once the I/O
completed—he saw some regression. So, delaying the release until a
later scan may allow swapcache hits before the folios are eventually
reclaimed.
But we actually have a problem here: this rotation, which puts
writeback folios at the tail of the LRU, is not reliable at all.
`folio_rotate_reclaimable()` would only work reliably if the endio
happens after the folio has been put back on the LRU head, rather than
while it is still isolated.
But nowadays NVMe is very fast. If we isolate N pages and perform
shrink on them, M pages may finish writeback during the isolation,
while the remaining N-M pages are still under writeback. M can easily
be more than 50% of N.
As a result, we can end up with the following cold/hot inversion:
LRU head
----- M pages whose writeback completed during isolation
----- other pages
----- N-M pages that are successfully rotated to the LRU tail
LRU tail
Now we can see that the M pages were expected to be reclaimed, but
they are not only left unreclaimed, but are effectively promoted to
the LRU head.
For MGLRU, commit 359a5e1416ca ("mm: multi-gen LRU: retry folios
written back while isolated") added the following code to reclaim
those M pages that finish writeback during isolation by retrying
`shrink_folio_list()` on them:
/* retry folios that may have missed
folio_rotate_reclaimable() */
if (!skip_retry && !folio_test_active(folio) &&
!folio_mapped(folio) &&
!folio_test_dirty(folio) && !folio_test_writeback(folio)) {
list_move(&folio->lru, &clean);
continue;
}
This somehow resolves the cold/hot inversion, but leaves the M and
N-M pages with inconsistent behavior: some are actually reclaimed,
while others remain at the tail of the LRU.
For the active/inactive LRU and `MADV_PAGEOUT`, we don't have a
mechanism to restore the missed reclaim opportunity. Ridong's patch[1]
addresses this cold/hot inversion in the active/inactive LRU reclaim
path. To my knowledge, there has never been a patch to address the
same cold/hot inversion in `MADV_PAGEOUT`.
BTW, if `MADV_PAGEOUT` is an explicit hint from userspace to reclaim
the memory, would it make sense to skip the later scan and reclaim the
folios immediately once the I/O completes?
[1] https://lore.kernel.org/linux-mm/20260920132519.3369946-1-ridong.chen@xxxxxxxxx/
Best Regards
Barry