Re: [PATCH mm-new v2] mm: mglru: clear the reference counter for rejected folios

From: Kairui Song

Date: Mon Sep 14 2026 - 05:00:18 EST


On Mon, Sep 14, 2026 at 4:24 PM Baolin Wang
<baolin.wang@xxxxxxxxxxxxxxxxx> wrote:
> On 9/14/26 4:09 PM, Kairui Song wrote:
> > On Wed, Sep 9, 2026 at 9:57 AM Baolin Wang
> > <baolin.wang@xxxxxxxxxxxxxxxxx> wrote:
> >>
> >> As per the comment on LRU_REFS_FLAGS, when accessed folios are promoted to
> >> a new generation, LRU_REFS_FLAGS should be cleared so that the reference
> >> counter can start over.
> >>
> >> For folios rejected by shrink_folio_list(), we clear LRU_REFS_FLAGS and
> >> set the PG_active flag when lru_gen_folio_seq() would place them in the
> >> oldest generation. That's fine.
> >>
> >> But for rejected folios where lru_gen_folio_seq() returns a generation
> >> other than the oldest one (which can be treated as a promotion), we do
> >> not clear LRU_REFS_FLAGS. This can violate the promotion mechanism. And
> >> this means the rejected folio enters the new generation with stale, inflated
> >> tier bits, which can inflate reference counts and distort eviction
> >> statistics for these rejected folios.
> >>
> >> Fix this by clearing LRU_REFS_FLAGS for rejected folios. Of course, I need
> >> to evaluate the impact of the changes, which mainly falls into 3 cases:
> >> 1. When lru_gen_folio_seq() returns the oldest generation for rejected folios,
> >> there are no logic changes, and they will be put back into the 2nd youngest
> >> generation.
> >> 2. For rejected folios with PG_active set by shrink_folio_list(), we only
> >> clear the LRU_REFS_FLAGS and do not change the generation.
> >> 3. For rejected folios with PG_referenced set, the original code would put
> >> them back into the 2nd oldest generation. After this patch, we will put them
> >> back into the 2nd youngest generation.
> >>
> >> I think case 3 is also reasonable, before commmit 6cbdd9726fb5 ("mm/mglru:
> >> use folio_mark_accessed to replace folio_set_active"), a rejected referenced
> >> folio was also put back to the 2nd youngest gen. Meanwhile, I didn't see
> >> any noticeable performance impact on my 32-core Arm machine when running
> >> 'make -j32' to build the kernel inside a 3G-limited memcg with either zram
> >> or NVMe swap.
> >>
> >> Signed-off-by: Baolin Wang <baolin.wang@xxxxxxxxxxxxxxxxx>
> >> ---
> >> Changes from v1:
> >> - Update the commit message.
> >> - Clear LRU_REFS_FLAGS earlier.
> >> ---
> >> mm/vmscan.c | 7 ++++---
> >> 1 file changed, 4 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/mm/vmscan.c b/mm/vmscan.c
> >> index 40d3f1b48a74..1557679aadb1 100644
> >> --- a/mm/vmscan.c
> >> +++ b/mm/vmscan.c
> >> @@ -5020,11 +5020,12 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
> >> continue;
> >> }
> >>
> >> + /* See the comments on LRU_REFS_FLAGS */
> >> + folio_set_lru_refs(folio, 0);
> >> +
> >
> > Will it be better to mention that we never add the folio to the oldest
> > gen (since `folio_set_active` below prevents that) so this is
> > effectively promotes the folio by at least one generation? Maybe can
> > be combined with the comment below.
>
> OK. How about the following comments?
>
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index c2eb8fa9d5e5..a1ead7c61054 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -5071,10 +5071,13 @@ static int evict_folios(unsigned long
> nr_to_scan, struct lruvec *lruvec,
> continue;
> }
>
> - /* See the comments on LRU_REFS_FLAGS */
> + /*
> + * See the comments on LRU_REFS_FLAGS.
> + *
> + * The rejected folios are never added to the oldest
> generation,
> + * so this effectively promotes them by at least one
> generation.
> + */

It looks good to me, thanks!