Re: [PATCH mm-unstable v3 2/2] mm/vmscan: apply too_many_isolated() throttling to MGLRU eviction
Barry Song <[email protected]>
| Newsgroups | gmane.linux.kernel,gmane.linux.kernel.mm |
|---|---|
| Message-ID | <CAGsJ_4xKM1R95TEpKoicGYQB8Qafez6hKJF=Z98A_2j43X5GAA@mail.gmail.com> |
On Tue, Aug 18, 2026 at 8:49 PM Hui Zhu <[email protected]> wrote: > > From: Hui Zhu <[email protected]> > > 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. BTW, if we are hitting isolated > inactive with MGLRU, it probably means the generations are quite imbalanced—we are running out of reclaimable generations. In that case, we may actually want reclamation to proceed with aging instead. > If a fatal signal is pending, fake reclaim progress the same way the > legacy path does, so the dying task exits reclaim quickly instead of > being held in the throttle. > > Signed-off-by: Hui Zhu <[email protected]> > --- > mm/vmscan.c | 71 ++++++++++++++++++++++++++++++++++++++++++++--------- > 1 file changed, 59 insertions(+), 12 deletions(-) > > diff --git a/mm/vmscan.c b/mm/vmscan.c > index 98226bb021f3..6fe8824430ac 100644 > --- a/mm/vmscan.c > +++ b/mm/vmscan.c > @@ -1819,7 +1819,7 @@ bool folio_isolate_lru(struct folio *folio) > * the LRU list will go small and be scanned faster than necessary, leading to > * unnecessary swapping, thrashing and OOM. > */ > -static bool too_many_isolated(struct pglist_data *pgdat, int file, > +static bool too_many_isolated(struct pglist_data *pgdat, bool file, > struct scan_control *sc) > { > unsigned long inactive, isolated; > @@ -1856,6 +1856,37 @@ static bool too_many_isolated(struct pglist_data *pgdat, int file, > return too_many; > } > > +/* > + * Throttle reclaim if too many isolated folios are piling up. If this makes > + * no progress, the caller is probably looping on unevictable folios, so give > + * up. Returns true to tell the caller to stop reclaiming, and sets @fatal > + * if the task received a fatal signal while waiting, so that the caller can > + * bail out faster. > + */ > +static bool throttle_is_throttled(struct pglist_data *pgdat, bool file, > + struct scan_control *sc, bool *fatal) > +{ > + bool stalled = false; > + > + *fatal = false; TBH, I find the name quite weird :-) Best Regards Barry