Re: [PATCH mm-unstable v3 2/2] mm/vmscan: apply too_many_isolated() throttling to MGLRU eviction
From: Barry Song
Date: Wed Aug 19 2026 - 18:02:07 EST
On Wed, Aug 19, 2026 at 5:30 PM Kairui Song <ryncsn@xxxxxxxxx> wrote:
>
> On Wed, Aug 19, 2026 at 10:15 AM Baolin Wang
> <baolin.wang@xxxxxxxxxxxxxxxxx> wrote:
> > On 8/19/26 6:06 AM, Barry Song wrote:
> > > On Tue, Aug 18, 2026 at 8:49 PM Hui Zhu <hui.zhu@xxxxxxxxx> wrote:
> > >>
> > >> From: Hui Zhu <zhuhui@xxxxxxxxxx>
> > >>
> > >> The legacy path throttles direct reclaim in shrink_inactive_list()
> > >> when too many isolated folios pile up, but MGLRU's evict_folios()
> > >> isolates folios without this check, which can lead to unnecessary
> > >> swapping, thrashing and OOM.
> > >>
> > >> With the NR_ISOLATED counters now updated in evict_folios(), extract
> > >> the throttling loop from shrink_inactive_list() into
> > >> throttle_is_throttled() and reuse it in evict_folios(). Since the
> > >> type to isolate is unknown until isolation and isolate_folios() may
> > >> fall back to the other type, check all evictable types with
> > >> for_each_evictable_type() and throttle if any of them has too many
> > >> isolated folios.
> > >>
> > >
> > > I feel this is unlikely to work. MGLRU behaves quite differently from the
> > > active/inactive LRU, and its `NR_INACTIVE_FILE` accounting is also very
> > > different.
> > >
> > > With the active/inactive LRU, shrink_inactive_list() ensures that we
> > > always have an inactive list with pages available for reclaim. With MGLRU,
> > > however, a generation can legitimately point to an empty list, so this
> > > assumption does not hold.
> > >
> > > try_to_inc_min_seq:
> > >
> > > /* see the comment on lru_gen_folio */
> > > if (swappiness && swappiness <= MAX_SWAPPINESS) {
> > > unsigned long seq = lrugen->max_seq - MIN_NR_GENS;
> > >
> > > if (min_seq[LRU_GEN_ANON] > seq && min_seq[LRU_GEN_FILE] < seq)
> > > min_seq[LRU_GEN_ANON] = seq;
> > > else if (min_seq[LRU_GEN_FILE] > seq &&
> > > min_seq[LRU_GEN_ANON] < seq)
> > > min_seq[LRU_GEN_FILE] = seq;
> > > }
> > >
> > > At that point, we have no inactive pages for the type, so the
> > > throttle will take effect when the following condition is true:
> > >
> > > too_many = isolated > inactive;
> > >
> > > With MGLRU, however, we can still fall back to the other type even
> > > when there are no inactive pages for the current type.
>
> Hi All, that's a very insightful concern.
>
> But on a higher level, you can fall back to the other type regardless
> of the LRU? That's not something limited to MGLRU I think? I mean
> throttling on one type seems like a good idea if the other type is
> very reclaimable.
I don't know how to throttle a type, since the throttle applies to a
thread rather than a type. Once the thread goes to sleep, it has no way
to fall back to the other type until it wakes up again.
>
> >
> > Yes, that's a valid concern. So I think we can check the isolation of
> > both types for MGLRU to avoid this case:
>
> ...
>
> >
> > The typical 'isolated > inactive' case is that we've tried our best with
> > aging, but cold pages production can't keep up with isolation speed,
> > especially under concurrent reclaim from multiple processes. In this
> > case, I think throttling is reasonable.
>
> Just an idea... How about we simplify this: just check the isolated vs
> total memory size? At least for MGLRU. MGLRU maintains NR_INACTIVE_*
> only as a compatibility shim for reporting meminfo, so it does not
> track the immediately reclaimable set the way the active/inactive LRU
> does, so the inactive value is a poor trigger for MGLRU: Aging moves
> the folios in batches so anonymous reading can be very jumpy. For file
> folios, PID can only promote unmapped page cache to the second oldest
> generation, meaning most file folios are considered inactive. This has
> been causing trouble for our dashboards for a long time and I think we
> can fix this by using the tier number intead of gen number as the
> inactive / active reading, that 's a different topic though.
>
> And in fact I don't quite get why classical LRU only compares that
> isolated number to the inactive count only. The reclamer can move
> active folios to the inactive part anytime, so throttling when we are
> low on inactive doesn't always seem like a good idea?
>
> I remember this was discussed sometime ago that in the long term we
> might better throttle it in a different way, it was once mentioned by
> Shakeel:
> https://lore.kernel.org/linux-mm/ahncWUAJlPZhNGr8@xxxxxxxxx/
>
> So perhaps we can throttle MGLRU more gently? e.g. just compare to the
> total number / MIN_NR_GENS, which means half of the memory is isolated
> for MGLRU? This doesn't look too pretty but I think it's better than
> using the inactive count for MGLRU. And if we introduce some
> gen-balance-based aging (whether that is a good idea is also another
> topic), the ideal goal of MGLRU will be evenly ditribute folios among
> gens so the current inactive reading will always target half of the
> total memory.
Yep, I think we can probably find a way:
* Throttle if the total number of isolated file and anon folios is too
high compared with their combined totals.
* Throttle if both file and anon have too many isolated folios compared
with their respective totals.
Either approach sounds good to me. Also I agree that inactive
accounting is really unreliable in MGLRU.
>
> Another thing btw is that the function name throttle_is_throttled
> reads a bit strange to me :)
Best Regards
Barry