Re: [PATCH v3 4/4] mm/mglru: fix anon-only reclaim evicting file pages when swappiness=max
From: Barry Song
Date: Thu Jul 23 2026 - 05:02:21 EST
On Thu, Jul 23, 2026 at 12:58 PM Ridong <ridong.chen@xxxxxxxxx> wrote:
>
> From: Ridong Chen <chenridong@xxxxxxxxxx>
>
> The previous patch fixed this issue for the traditional LRU. The same
> problem exists in MGLRU [1]: when swappiness=max (SWAPPINESS_ANON_ONLY)
> is set, reclaim is expected to evict anonymous pages exclusively, but
> file pages can still be reclaimed when anonymous pages cannot be
> reclaimed (e.g. no swap and no demotion target).
>
> With SWAPPINESS_ANON_ONLY, get_type_to_scan() always returns
> LRU_GEN_ANON and for_each_evictable_type() only iterates the anon type.
> But if get_nr_to_scan() does not bail out, evict_folios() still runs and
> isolate_folios() falls back to scanning file pages in the !scanned case:
>
> shrink_one
> try_to_shrink_lruvec
> get_swappiness // returns SWAPPINESS_ANON_ONLY for swappiness=max
> get_nr_to_scan
> evict_folios
> isolate_folios // falls back to file type when !scanned
>
I am not convinced this is correct. Although we do have `type = !type`,
when `swappiness == 201`, `for_each_evictable_type()` stops iterating
after trying a single type, so there is no opportunity to fall back.
#define for_each_evictable_type(type, swappiness) \
for ((type) = min_type(swappiness); (type) <=
max_type(swappiness); (type)++)
So I'm really curious what's happening here.
static int isolate_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
struct scan_control *sc, int swappiness,
struct list_head *list, int *isolated,
int *isolate_type, int *isolate_scanned)
{
int i;
int total_scanned = 0;
int type = get_type_to_scan(lruvec, swappiness);
for_each_evictable_type(i, swappiness) {
int scanned;
int tier = get_tier_idx(lruvec, type);
scanned = scan_folios(nr_to_scan, lruvec, sc,
type, tier, list, isolated);
...
if (!scanned)
type = !type;
}
return total_scanned;
}
since both min and max types are anon:
#define min_type(swappiness) (!(swappiness))
#define max_type(swappiness) ((swappiness) < SWAPPINESS_ANON_ONLY)
I guess the real problem only occurs when `may_swap` is false?
Thanks
barry