Re: [PATCH mm-unstable v3 2/2] mm/vmscan: apply too_many_isolated() throttling to MGLRU eviction
From: Barry Song
Date: Tue Aug 18 2026 - 18:11:43 EST
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.
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 <zhuhui@xxxxxxxxxx>
> ---
> 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