From: sashiko-bot@kernel.org
To: "Barry Song (Xiaomi)" <baohua@kernel.org>,
akpm@linux-foundation.org, linux-mm@kvack.org
Cc: hui.zhu@linux.dev, axelrasmussen@google.com,
baolin.wang@linux.alibaba.com, david@kernel.org,
hannes@cmpxchg.org, ljs@kernel.org, mhocko@kernel.org,
qi.zheng@linux.dev, ryncsn@gmail.com, shakeel.butt@linux.dev,
weixugc@google.com, yuanchu@google.com, zhuhui@kylinos.cn,
baoquan.he@linux.dev, liuxiang.277@bytedance.com,
wangzicheng@honor.com, lianux.mm@gmail.com, kasong@tencent.com,
liam@infradead.org, surenb@google.com, mhocko@suse.com,
rppt@kernel.org, zhangbo56@xiaomi.com, lyugaofei@xiaomi.com,
ridong.chen@linux.dev, kunwu.chan@gmail.com
Subject: Re: [RFC PATCH v5 05/14] mm/mglru: skip zones above reclaim_idx instead of rotating them
Date: Fri, 23 Oct 2026 22:03:37 +0000 [thread overview]
Message-ID: <sashiko-outbox-183271@kernel.org> (raw)
In-Reply-To: <20261022220203.91911-6-baohua@kernel.org>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] mm/mglru: pinned min_seq in higher zones stalls aging in scan_folios()
--
commit 1b2f683d6b8bd1e171eb9677315ba8a3d9431b9b
Author: Kairui Song <kasong@tencent.com>
mm/mglru: skip zones above reclaim_idx instead of rotating them
This commit restricts scan_folios() and lruvec_populated_min_seq() during
eviction to zones at or below sc->reclaim_idx, and removes the ineligible-zone
rotation branch from sort_folio(). try_to_inc_min_seq() continues to check all
zones up to MAX_NR_ZONES before advancing min_seq.
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index a365a4bc8c988..09ea72b354a56 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -4132,7 +4132,7 @@ static bool inc_min_seq(struct lruvec *lruvec, int type, int swappiness)
>
> /* Similar to lruvec_evictable_size, return the oldest populated seq of the type */
> static unsigned long lruvec_populated_min_seq(struct lruvec *lruvec, int type,
> - unsigned long max_seq)
> + int zone_limit, unsigned long max_seq)
> {
> int gen, zone;
> unsigned long min_seq;
> @@ -4143,7 +4143,7 @@ static unsigned long lruvec_populated_min_seq(struct lruvec *lruvec, int type,
> min_seq = READ_ONCE(lrugen->min_seq[type]);
> while (min_seq <= max_seq) {
> gen = lru_gen_from_seq(min_seq);
> - for (zone = 0; zone < MAX_NR_ZONES; zone++) {
> + for (zone = 0; zone < zone_limit; zone++) {
> if (!list_empty(&lrugen->folios[gen][type][zone]))
> return min_seq;
> }
> @@ -4166,7 +4166,7 @@ static void try_to_inc_min_seq(struct lruvec *lruvec, int swappiness)
> /* Requires at least MIN_NR_GENS gens for basic functionality */
> seq = lrugen->max_seq - MIN_NR_GENS;
> for_each_evictable_type(type, swappiness) {
> - min_seq[type] = lruvec_populated_min_seq(lruvec, type, seq + 1);
> + min_seq[type] = lruvec_populated_min_seq(lruvec, type, MAX_NR_ZONES, seq + 1);
> if (min_seq[type] > lrugen->min_seq[type])
> seq_inc_flag = true;
> }
[ ... ]
> @@ -4863,10 +4864,8 @@ static bool sort_folio(struct lruvec *lruvec, struct folio *folio, struct scan_c
> * longer be promoted or protected, so just isolate them. The one
> * exception is lru_gen_reparent_memcg(), which is handled above.
> */
> - if (min_gen == max_gen) {
> - VM_WARN_ON_ONCE(zone > sc->reclaim_idx);
> + if (min_gen == max_gen)
> return false;
> - }
>
> /* protected */
> if (tier > tier_idx || refs + workingset == BIT(LRU_REFS_WIDTH) + 1) {
> @@ -4883,13 +4882,6 @@ static bool sort_folio(struct lruvec *lruvec, struct folio *folio, struct scan_c
> return true;
> }
>
> - /* ineligible */
> - if (zone > sc->reclaim_idx) {
> - gen = folio_inc_gen(lruvec, folio, min_gen);
> - list_move_tail(&folio->lru, &lrugen->folios[gen][type][zone]);
> - return true;
> - }
> -
> return false;
> }
>
> @@ -4921,16 +4913,17 @@ static int scan_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
> struct scan_control *sc, int type, int tier,
> struct list_head *list, int *isolatedp)
> {
> - int i;
> enum node_stat_item item;
> + int zone_idx;
> int sorted = 0;
> int scanned = 0;
> int isolated = 0;
> int skipped = 0;
> int gen, max_gen;
> - unsigned long min_seq;
> + unsigned long seq;
> unsigned long remaining = nr_to_scan;
> struct lru_gen_folio *lrugen = &lruvec->lrugen;
> + struct pglist_data *pgdat = lruvec_pgdat(lruvec);
> DEFINE_MAX_SEQ(lruvec);
>
> VM_WARN_ON_ONCE(nr_to_scan > MAX_LRU_BATCH);
> @@ -4942,24 +4935,22 @@ static int scan_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
> * when under pressure to respect swappiness more and reduce IO cost.
> */
> if (sc->priority == DEF_PRIORITY)
> - min_seq = lrugen->min_seq[type];
> + seq = lrugen->min_seq[type];
> else
> - min_seq = lruvec_populated_min_seq(lruvec, type, lrugen->max_seq);
> + seq = lrugen->max_seq;
>
> - gen = lru_gen_from_seq(min_seq);
> + seq = lruvec_populated_min_seq(lruvec, type, sc->reclaim_idx + 1, seq);
> + gen = lru_gen_from_seq(seq);
> max_gen = lru_gen_from_seq(max_seq);
>
> - for (i = MAX_NR_ZONES; i > 0; i--) {
> + /* Scan eligible zones in descending order. */
> + for (zone_idx = sc->reclaim_idx; zone_idx >= 0; zone_idx--) {
[Severity: High]
During zone-constrained reclaim in mm/vmscan.c (where sc->reclaim_idx is below
MAX_NR_ZONES - 1 and zones above sc->reclaim_idx are populated, such as
GFP_DMA32 reclaim with a populated ZONE_NORMAL or GFP_KERNEL reclaim with a
populated ZONE_MOVABLE), can keeping MAX_NR_ZONES in try_to_inc_min_seq()
while removing the ineligible-zone rotation from sort_folio() stall aging and
memcg rotation?
Previously, scan_folios() visited all zones and sort_folio() rotated folios in
zones above sc->reclaim_idx from min_gen to min_gen + 1. Once the oldest
generation was emptied across all zones, try_to_inc_min_seq() incremented
lrugen->min_seq[type] from max_seq - 3 (when MAX_NR_GENS generations exist) to
max_seq - 2, allowing should_run_aging() to trigger try_to_inc_max_seq().
With scan_folios() restricted to zones 0..sc->reclaim_idx, folios in zones
above sc->reclaim_idx remain in min_seq[type]. Because try_to_inc_min_seq()
still passes MAX_NR_ZONES to lruvec_populated_min_seq(), lrugen->min_seq[type]
stays pinned at max_seq - 3 even after min_seq[type] is completely drained in
eligible zones 0..sc->reclaim_idx.
In this commit, at sc->priority == DEF_PRIORITY, scan_folios() caps the
lruvec_populated_min_seq() search bound at seq = lrugen->min_seq[type]. Once
min_seq[type] is empty in zones 0..sc->reclaim_idx, lruvec_populated_min_seq()
still returns the pinned min_seq[type], so scan_folios() scans empty lists and
returns 0 at DEF_PRIORITY.
A later commit in this series ("mm/mglru: lift youngest gen protection for
higher priority") changes the DEF_PRIORITY search bound in scan_folios() to
lrugen->max_seq - 1, and another commit ("mm/mglru: Run aging when pages are
rare outside the youngest gen") adds lru_gen_imbalanced() to
should_run_aging(). However, both should_run_aging() and shrink_one() still
rely on state across all zones:
mm/vmscan.c:should_run_aging() {
DEFINE_MIN_SEQ(lruvec);
/* have to run aging, since eviction is not possible anymore */
if (evictable_min_seq(min_seq, swappiness) + MIN_NR_GENS > max_seq)
return true;
/* try to avoid aging, do gentle reclaim at the default priority */
if (sc->priority == DEF_PRIORITY)
return false;
/* better to run aging even though eviction is still possible */
return evictable_min_seq(min_seq, swappiness) + MIN_NR_GENS == max_seq;
}
mm/vmscan.c:shrink_one() {
...
need_rotate = try_to_shrink_lruvec(lruvec, sc);
...
if (need_rotate && mem_cgroup_online(memcg))
return MEMCG_LRU_YOUNG;
if (!need_rotate && lruvec_is_sizable(lruvec, sc))
return 0;
}
When lrugen->min_seq[type] remains pinned at max_seq - 3 by folios in zones
above sc->reclaim_idx (and lru_gen_imbalanced() / lruvec_is_sizable() sum
nr_pages across all MAX_NR_ZONES):
1. should_run_aging() sees min_seq + MIN_NR_GENS < max_seq and does not run
try_to_inc_max_seq() (or inc_min_seq() inside inc_max_seq()), stalling
page-table aging.
2. Once eligible zones 0..sc->reclaim_idx drain their older generations and
lruvec_populated_min_seq() advances seq to max_seq in scan_folios(),
sort_folio() hits min_gen == max_gen and isolates folios from the youngest
generation without tier or reference protection.
3. If a memcg has no folios in eligible zones 0..sc->reclaim_idx but has
folios in zones above sc->reclaim_idx, try_to_shrink_lruvec() returns
need_rotate = false while lruvec_is_sizable() returns true, so shrink_one()
returns 0 instead of rotating the memcg.
Should should_run_aging() and the size checks also account for sc->reclaim_idx,
or how should min_seq and max_seq advance when older generations are only
populated in zones above sc->reclaim_idx?
[ ... ]
([PVF1])
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261022220203.91911-1-baohua@kernel.org?part=5
next prev parent reply other threads:[~2026-10-23 22:03 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-22 22:01 [RFC PATCH v5 00/14] mm: mglru: fix swappiness behavior Barry Song (Xiaomi)
2026-10-22 22:01 ` [RFC PATCH v5 01/14] mm/mglru: report evictable sizes per type Barry Song (Xiaomi)
2026-10-27 8:51 ` KunWu Chan
2026-10-22 22:01 ` [RFC PATCH v5 02/14] mm/mglru: extract lruvec_populated_min_seq() helper Barry Song (Xiaomi)
2026-10-27 9:39 ` KunWu Chan
2026-10-22 22:01 ` [RFC PATCH v5 03/14] mm/mglru: reclaim from the oldest populated gen Barry Song (Xiaomi)
2026-10-27 9:56 ` KunWu Chan
2026-10-22 22:01 ` [RFC PATCH v5 04/14] mm/mglru: lift the forced protection of reclaimer Barry Song (Xiaomi)
2026-10-28 4:14 ` KunWu Chan
2026-10-22 22:01 ` [RFC PATCH v5 05/14] mm/mglru: skip zones above reclaim_idx instead of rotating them Barry Song (Xiaomi)
2026-10-23 22:03 ` sashiko-bot [this message]
2026-10-24 16:19 ` Kairui Song
2026-10-22 22:01 ` [RFC PATCH v5 06/14] mm/mglru: return for unavailable anon reclaim earlier Barry Song (Xiaomi)
2026-10-22 22:01 ` [RFC PATCH v5 07/14] mm/mglru: balance anon and file scan budget by refault rate Barry Song (Xiaomi)
2026-10-23 22:03 ` sashiko-bot
2026-10-24 16:24 ` Kairui Song
2026-10-26 7:34 ` Barry Song
2026-10-22 22:01 ` [RFC PATCH v5 08/14] mm/mglru: lift youngest gen protection for higher priority Barry Song (Xiaomi)
2026-10-23 22:03 ` sashiko-bot
2026-10-24 18:08 ` Kairui Song
2026-10-22 22:01 ` [RFC PATCH v5 09/14] mm/mglru: Avoid placing rejected folios below populated gen Barry Song (Xiaomi)
2026-10-22 22:01 ` [RFC PATCH v5 10/14] mm/mglru: Run aging when pages are rare outside the youngest gen Barry Song (Xiaomi)
2026-10-22 22:02 ` [RFC PATCH v5 11/14] mm/mglru: Reduce LRU lock contention by shrinking folio batches in inc_min_seq Barry Song (Xiaomi)
2026-10-22 22:02 ` [RFC PATCH v5 12/14] mm/mglru: Avoid prolonged anon reclaim with swappiness=200 Barry Song (Xiaomi)
2026-10-22 22:02 ` [RFC PATCH v5 13/14] mm/mglru: Make swappiness=1 file reclaim more aggressive Barry Song (Xiaomi)
2026-10-22 22:02 ` [RFC PATCH v5 14/14] mm/mglru: Avoid scan anon while swapcache is low for GFP_NOIO allocation Barry Song (Xiaomi)
2026-10-23 22:03 ` sashiko-bot
2026-10-25 1:31 ` Bo Zhang
2026-10-26 8:43 ` KunWu Chan
2026-10-24 16:10 ` [RFC PATCH v5 00/14] mm: mglru: fix swappiness behavior Kairui Song
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-183271@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=axelrasmussen@google.com \
--cc=baohua@kernel.org \
--cc=baolin.wang@linux.alibaba.com \
--cc=baoquan.he@linux.dev \
--cc=david@kernel.org \
--cc=hannes@cmpxchg.org \
--cc=hui.zhu@linux.dev \
--cc=kasong@tencent.com \
--cc=kunwu.chan@gmail.com \
--cc=liam@infradead.org \
--cc=lianux.mm@gmail.com \
--cc=linux-mm@kvack.org \
--cc=liuxiang.277@bytedance.com \
--cc=ljs@kernel.org \
--cc=lyugaofei@xiaomi.com \
--cc=mhocko@kernel.org \
--cc=mhocko@suse.com \
--cc=qi.zheng@linux.dev \
--cc=ridong.chen@linux.dev \
--cc=rppt@kernel.org \
--cc=ryncsn@gmail.com \
--cc=sashiko-reviews@lists.linux.dev \
--cc=shakeel.butt@linux.dev \
--cc=surenb@google.com \
--cc=wangzicheng@honor.com \
--cc=weixugc@google.com \
--cc=yuanchu@google.com \
--cc=zhangbo56@xiaomi.com \
--cc=zhuhui@kylinos.cn \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox