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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.