Re: [PATCH mm-new v9] mm: vmscan: retry folios written back while isolated for traditional LRU
From: Barry Song
Date: Fri Sep 18 2026 - 05:48:55 EST
On Fri, Sep 18, 2026 at 10:12 AM Ridong Chen <ridong.chen@xxxxxxxxx> wrote:
[...]
> >
> > I wouldn't necessarily call it a fix, as keeping the swap cache for
> > those folios can sometimes help with future hits. For example, we may
> > hit those folios again before they are reclaimed. So it's a
> > double-edged sword.
> >
> > That said, the cold/hot inversion is a real problem that we should
> > fix. Ideally, we should find a way to restore the missed
> > `folio_rotate_reclaimable()` behavior, conceptually something like:
> >
> > diff --git a/mm/vmscan.c b/mm/vmscan.c
> > index fde28d0a647d..5ee296474b48 100644
> > --- a/mm/vmscan.c
> > +++ b/mm/vmscan.c
> > @@ -891,7 +891,10 @@ long remove_mapping(struct address_space
> > *mapping, struct folio *folio)
> > */
> > void folio_putback_lru(struct folio *folio)
> > {
> > - folio_add_lru(folio);
> > + if (folio_has_been_writtenback_due_reclaim(folio))
> > + folio_add_lru_tail(folio);
> > + else
> > + folio_add_lru(folio);
> > folio_put(folio); /* drop ref from isolate */
> > }
> >
>
> That is a good idea. But I am not sure I can find the correct way to do it. I
> will give it a try and get back to you.
>
Maybe something like the below? I haven't tested it.
diff --git a/mm/vmscan.c b/mm/vmscan.c
index fde28d0a647d..906db7d8c043 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1942,7 +1942,7 @@ static bool too_many_isolated(struct pglist_data *pgdat, int file,
*
* Note: The caller must not hold any lruvec lock.
*/
-static unsigned int move_folios_to_lru(struct list_head *list)
+static unsigned int move_folios_to_lru(struct list_head *list, bool do_rotate)
{
int nr_pages, nr_moved = 0;
struct lruvec *lruvec = NULL;
@@ -1989,7 +1989,16 @@ static unsigned int move_folios_to_lru(struct list_head *list)
continue;
}
- lruvec_add_folio(lruvec, folio);
+ /*
+ * Put folios that may have missed folio_rotate_reclaimable() at the tail
+ * to avoid cold/hot inversion
+ */
+ if (do_rotate && !folio_test_active(folio) && !folio_mapped(folio) &&
+ !folio_test_dirty(folio) && !folio_test_writeback(folio))
+ lruvec_add_folio_tail(lruvec, folio);
+ else
+ lruvec_add_folio(lruvec, folio);
+
nr_pages = folio_nr_pages(folio);
nr_moved += nr_pages;
if (folio_test_active(folio))
@@ -2106,7 +2115,7 @@ static unsigned long shrink_inactive_list(unsigned long nr_to_scan,
nr_reclaimed = shrink_folio_list(&folio_list, pgdat, sc, &stat, false,
lruvec_memcg(lruvec));
- move_folios_to_lru(&folio_list);
+ move_folios_to_lru(&folio_list, true);
mod_lruvec_state(lruvec, PGDEMOTE_KSWAPD + reclaimer_offset(sc),
stat.nr_demoted);
@@ -2217,8 +2226,8 @@ static void shrink_active_list(unsigned long nr_to_scan,
/*
* Move folios back to the lru list.
*/
- nr_activate = move_folios_to_lru(&l_active);
- nr_deactivate = move_folios_to_lru(&l_inactive);
+ nr_activate = move_folios_to_lru(&l_active, false);
+ nr_deactivate = move_folios_to_lru(&l_inactive, false);
count_vm_events(PGDEACTIVATE, nr_deactivate);
count_memcg_events(lruvec_memcg(lruvec), PGDEACTIVATE, nr_deactivate);
@@ -5083,7 +5092,7 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
folio_set_active(folio);
}
- move_folios_to_lru(&list);
+ move_folios_to_lru(&list, true);
walk = current->reclaim_state->mm_walk;
if (walk && walk->batched) {