From: "Barry Song (Xiaomi)" <baohua@kernel.org>
To: akpm@linux-foundation.org, linux-mm@kvack.org
Cc: axelrasmussen@google.com, baolin.wang@linux.alibaba.com,
baoquan.he@linux.dev, hannes@cmpxchg.org, hui.zhu@linux.dev,
kasong@tencent.com, kunwu.chan@gmail.com, liam@infradead.org,
lianux.mm@gmail.com, linux-kernel@vger.kernel.org,
liuxiang.277@bytedance.com, lyugaofei@xiaomi.com,
mhocko@kernel.org, mhocko@suse.com, qi.zheng@linux.dev,
ridong.chen@linux.dev, rppt@kernel.org, ryncsn@gmail.com,
shakeel.butt@linux.dev, surenb@google.com, wangzicheng@honor.com,
weixugc@google.com, yuanchu@google.com, zhangbo56@xiaomi.com,
zhuhui@kylinos.cn, sidchintamaneni@gmail.com,
"Barry Song (Xiaomi)" <baohua@kernel.org>
Subject: [PATCH v9 11/16] mm/mglru: Run aging when one type is drained
Date: Sun, 15 Nov 2026 04:07:58 +0800 [thread overview]
Message-ID: <20261114200803.23129-12-baohua@kernel.org> (raw)
In-Reply-To: <20261114200803.23129-1-baohua@kernel.org>
We may have remaining scan budget for anon or file but no folios
in populatable generations to scan. In this case, `scan_folios()`
may repeatedly scan that type without making progress, even when
the other type still has populatable folios.
Run aging when a type is drained to make more folios available for
reclaim. This also helps honor the scan budget distribution
determined by swappiness.
Move aging after eviction to detect a lack of scan progress and
avoid unnecessary aging when eviction can still make progress.
To avoid excessive aging, allow drained aging only once per
`try_to_shrink_lruvec()` invocation. Also skip drained aging if
another reclaimer has advanced `max_seq` during eviction.
At extreme swappiness values such as 1 and 200, reclaim initially
focuses on the preferred type. Rely on imbalanced aging once
`sc->priority` reaches `DEF_PRIORITY / 2`, rather than triggering
drained aging for the unpreferred type. This avoids unnecessary
aging and has shown better performance in testing.
If `evict_folio_lists()` returns zero, retry eviction once if
`max_seq` has advanced since the aging decision.
Signed-off-by: Barry Song (Xiaomi) <baohua@kernel.org>
---
mm/vmscan.c | 49 +++++++++++++++++++++++++++++++++++++------------
1 file changed, 37 insertions(+), 12 deletions(-)
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 1450542d709c..6d942f192e63 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -5175,7 +5175,8 @@ static bool should_abort_scan(struct lruvec *lruvec, struct scan_control *sc)
}
static long evict_folio_lists(unsigned long nr_to_scan[], struct lruvec *lruvec,
- struct scan_control *sc, int swappiness, unsigned long max_batch)
+ struct scan_control *sc, int swappiness,
+ unsigned long max_batch, bool *drained)
{
int type;
unsigned long batch, scanned, total_scanned = 0;
@@ -5191,6 +5192,8 @@ static long evict_folio_lists(unsigned long nr_to_scan[], struct lruvec *lruvec,
batch = min(nr_to_scan[type], max_batch);
scanned = evict_folios(batch, lruvec, sc, type, swappiness);
+ if (drained && !scanned)
+ *drained = true;
nr_to_scan[type] -= min(nr_to_scan[type], scanned);
total_scanned += scanned;
}
@@ -5206,9 +5209,15 @@ static long evict_folio_lists(unsigned long nr_to_scan[], struct lruvec *lruvec,
static bool try_to_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
{
unsigned long nr[ANON_AND_FILE];
- bool need_rotate = false, should_age = false;
+ bool need_rotate = false, should_age = false, retried = false;
int swappiness = get_swappiness(lruvec, sc);
struct mem_cgroup *memcg = lruvec_memcg(lruvec);
+ /*
+ * Avoid aging the lagging, unpreferred type at extreme swappiness;
+ * rely on imbalanced aging once priority reaches AGING_PRIORITY
+ */
+ bool allow_drained_age = sc->priority < DEF_PRIORITY &&
+ swappiness > MIN_SWAPPINESS + 1 && swappiness < MAX_SWAPPINESS;
/*
* Proactive reclaim initiated by userspace for anonymous memory only.
@@ -5226,22 +5235,17 @@ static bool try_to_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
lru_gen_prepare_scan(lruvec, sc, memcg, swappiness, nr);
while (nr[LRU_GEN_ANON] > 0 || nr[LRU_GEN_FILE] > 0) {
+ bool drained = false, do_drained_age;
DEFINE_MAX_SEQ(lruvec);
+ unsigned long new_seq;
+ long scanned;
if (mem_cgroup_below_min(sc->target_mem_cgroup, memcg)) {
need_rotate = true;
break;
}
- if (should_run_aging(lruvec, max_seq, sc, swappiness)) {
- trace_mm_mglru_aging(lruvec, sc, swappiness);
- if (try_to_inc_max_seq(lruvec, max_seq, swappiness, false))
- need_rotate = true;
- should_age = true;
- }
-
- if (!evict_folio_lists(nr, lruvec, sc, swappiness, MIN_LRU_BATCH))
- break;
+ scanned = evict_folio_lists(nr, lruvec, sc, swappiness, MIN_LRU_BATCH, &drained);
if (should_abort_scan(lruvec, sc))
break;
@@ -5253,6 +5257,27 @@ static bool try_to_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
if (root_reclaim(sc) && should_age)
break;
+ /*
+ * Allow drained aging only once per invocation and skip it if
+ * max_seq advanced concurrently during eviction
+ */
+ new_seq = READ_ONCE(lruvec->lrugen.max_seq);
+ do_drained_age = drained && allow_drained_age && max_seq == new_seq;
+ allow_drained_age &= !do_drained_age;
+ if (do_drained_age || should_run_aging(lruvec, new_seq, sc, swappiness)) {
+ trace_mm_mglru_aging(lruvec, sc, swappiness);
+ if (try_to_inc_max_seq(lruvec, new_seq, swappiness, false))
+ need_rotate = true;
+ should_age = true;
+ }
+
+ if (!scanned) {
+ /* Retry once if aging advanced max_seq */
+ if (retried || new_seq == READ_ONCE(lruvec->lrugen.max_seq))
+ break;
+ retried = true;
+ }
+
cond_resched();
}
@@ -5885,7 +5910,7 @@ static int run_eviction(struct lruvec *lruvec, unsigned long seq, struct scan_co
lru_gen_balance_scan(lruvec, swappiness,
nr_to_reclaim - sc->nr_reclaimed, nr_to_scan);
- if (!evict_folio_lists(nr_to_scan, lruvec, sc, swappiness, MAX_LRU_BATCH))
+ if (!evict_folio_lists(nr_to_scan, lruvec, sc, swappiness, MAX_LRU_BATCH, NULL))
return 0;
cond_resched();
--
2.39.3 (Apple Git-146)
next prev parent reply other threads:[~2026-11-14 20:09 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-14 20:07 [PATCH v9 00/16] mm: mglru: fix swappiness behavior Barry Song (Xiaomi)
2026-11-14 20:07 ` [PATCH v9 01/16] mm/mglru: report evictable sizes per type Barry Song (Xiaomi)
2026-11-14 20:07 ` [PATCH v9 02/16] mm/mglru: extract lruvec_populated_min_seq() helper Barry Song (Xiaomi)
2026-11-14 20:07 ` [PATCH v9 03/16] mm/mglru: reclaim from the oldest populated gen Barry Song (Xiaomi)
2026-11-14 20:07 ` [PATCH v9 04/16] mm/mglru: lift the forced protection of reclaimer Barry Song (Xiaomi)
2026-11-14 20:07 ` [PATCH v9 05/16] mm/mglru: skip zones above reclaim_idx instead of rotating them Barry Song (Xiaomi)
2026-11-14 20:07 ` [PATCH v9 06/16] mm/mglru: return for unavailable anon reclaim earlier Barry Song (Xiaomi)
2026-11-14 20:07 ` [PATCH v9 07/16] mm/mglru: balance anon and file scan budget by refault rate Barry Song (Xiaomi)
2026-11-14 20:07 ` [PATCH v9 08/16] mm/mglru: lift youngest gen protection for higher priority Barry Song (Xiaomi)
2026-11-14 20:07 ` [PATCH v9 09/16] mm/mglru: Avoid placing rejected folios below populated gen Barry Song (Xiaomi)
2026-11-14 20:07 ` [PATCH v9 10/16] mm/mglru: Run aging when pages are rare outside the youngest gen Barry Song (Xiaomi)
2026-11-14 20:07 ` Barry Song (Xiaomi) [this message]
2026-11-14 20:50 ` [PATCH v9 11/16] mm/mglru: Run aging when one type is drained sashiko-bot
2026-11-14 20:07 ` [PATCH v9 12/16] mm/mglru: Restrict eviction accounting to eligible zones Barry Song (Xiaomi)
2026-11-14 20:08 ` [PATCH v9 13/16] mm/mglru: Reduce LRU lock contention by shrinking folio batches in inc_min_seq Barry Song (Xiaomi)
2026-11-14 20:08 ` [PATCH v9 14/16] mm/mglru: Avoid prolonged anon reclaim with swappiness=200 Barry Song (Xiaomi)
2026-11-14 20:08 ` [PATCH v9 15/16] mm/mglru: Make swappiness=1 file reclaim more aggressive Barry Song (Xiaomi)
2026-11-14 20:08 ` [PATCH v9 16/16] mm/mglru: Avoid scan anon while swapcache is low for GFP_NOIO allocation Barry Song (Xiaomi)
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=20261114200803.23129-12-baohua@kernel.org \
--to=baohua@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=axelrasmussen@google.com \
--cc=baolin.wang@linux.alibaba.com \
--cc=baoquan.he@linux.dev \
--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-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=liuxiang.277@bytedance.com \
--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=shakeel.butt@linux.dev \
--cc=sidchintamaneni@gmail.com \
--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