From: Ridong <ridong.chen@linux.dev>
To: Andrew Morton <akpm@linux-foundation.org>,
Johannes Weiner <hannes@cmpxchg.org>
Cc: David Hildenbrand <david@kernel.org>,
Michal Hocko <mhocko@kernel.org>, Qi Zheng <qi.zheng@linux.dev>,
Shakeel Butt <shakeel.butt@linux.dev>,
Lorenzo Stoakes <ljs@kernel.org>,
Kairui Song <kasong@tencent.com>, Barry Song <baohua@kernel.org>,
Axel Rasmussen <axelrasmussen@google.com>,
Yuanchu Xie <yuanchu@google.com>, Wei Xu <weixugc@google.com>,
Yu Zhao <yuzhao@google.com>,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
Ridong Chen <ridong.chen@linux.dev>,
Ridong Chen <chenridong@xiaomi.com>
Subject: [PATCH] mm/mglru: fix memcg protection for global proactive reclaim
Date: Thu, 23 Jul 2026 21:05:59 +0800 [thread overview]
Message-ID: <20260723130559.2343690-1-ridong.chen@linux.dev> (raw)
From: Ridong Chen <chenridong@xiaomi.com>
memory.min/low is silently bypassed for MGLRU during global proactive
reclaim (writing to the root memory.reclaim). It can be reproduced as
follows:
# echo 7 > /sys/kernel/mm/lru_gen/enabled
# cd /sys/fs/cgroup
# mkdir -p a/b
# echo 100M > a/memory.min
# echo +memory > a/cgroup.subtree_control
# echo 100M > a/b/memory.min
# echo $$ > a/b/cgroup.procs
# dd if=/dev/zero of=/tmp/testfile bs=1M count=200
# cat a/b/memory.current
222650368
# echo 500M > memory.reclaim
-bash: echo: write error: Resource temporarily unavailable
# cat a/b/memory.current
6070272
memory.min is 100M, yet reclaim drops a/b down to 6M, breaking the
protection. The traditional LRU is not affected.
Commit 30d77b7eef01 ("mm/mglru: fix ineffective protection calculation")
computes the memcg protection in lru_gen_age_node(), which only runs for
kswapd. Global proactive reclaim reaches shrink_one() through
lru_gen_shrink_node() without any aging step, so emin/elow is not
couputed,
Factor the tree traversal out into update_memcg_protection() and call
it from lru_gen_shrink_node() for the non-kswapd path, so the protection
is computed before shrinking. kswapd keeps computing it in
lru_gen_age_node(), which also needs it for the min_ttl OOM check.
Fixes: e4dde56cd208 ("mm: multi-gen LRU: per-node lru_gen_folio lists")
Signed-off-by: Ridong Chen <chenridong@xiaomi.com>
---
mm/vmscan.c | 33 +++++++++++++++++++++++++--------
1 file changed, 25 insertions(+), 8 deletions(-)
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 06e103f9781e..dc3549583e97 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -4122,6 +4122,16 @@ static bool lruvec_is_reclaimable(struct lruvec *lruvec, struct scan_control *sc
return time_is_before_jiffies(birth + min_ttl);
}
+static void update_memcg_protection(void)
+{
+ struct mem_cgroup *memcg;
+
+ memcg = mem_cgroup_iter(NULL, NULL, NULL);
+ do {
+ mem_cgroup_calculate_protection(NULL, memcg);
+ } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)));
+}
+
/* to protect the working set of the last N jiffies */
static unsigned long lru_gen_min_ttl __read_mostly;
@@ -4135,15 +4145,19 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc)
set_initial_priority(pgdat, sc);
- memcg = mem_cgroup_iter(NULL, NULL, NULL);
- do {
- struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat);
+ update_memcg_protection();
- mem_cgroup_calculate_protection(NULL, memcg);
+ if (min_ttl) {
+ memcg = mem_cgroup_iter(NULL, NULL, NULL);
+ do {
+ struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat);
- if (!reclaimable)
- reclaimable = lruvec_is_reclaimable(lruvec, sc, min_ttl);
- } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)));
+ if (lruvec_is_reclaimable(lruvec, sc, min_ttl)) {
+ reclaimable = true;
+ break;
+ }
+ } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)));
+ }
/*
* The main goal is to OOM kill if every generation from all memcgs is
@@ -5004,7 +5018,7 @@ static int shrink_one(struct lruvec *lruvec, struct scan_control *sc)
struct mem_cgroup *memcg = lruvec_memcg(lruvec);
struct pglist_data *pgdat = lruvec_pgdat(lruvec);
- /* lru_gen_age_node() called mem_cgroup_calculate_protection() */
+ /* update_memcg_protection() computed the protection */
if (mem_cgroup_below_min(NULL, memcg))
return MEMCG_LRU_YOUNG;
@@ -5151,8 +5165,11 @@ static void lru_gen_shrink_node(struct pglist_data *pgdat, struct scan_control *
set_initial_priority(pgdat, sc);
+ /* kswapd called update_memcg_protection in lru_gen_age_node */
if (current_is_kswapd())
sc->nr_reclaimed = 0;
+ else
+ update_memcg_protection();
if (mem_cgroup_disabled())
shrink_one(&pgdat->__lruvec, sc);
--
2.34.1
next reply other threads:[~2026-07-23 13:06 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-23 13:05 Ridong [this message]
2026-07-23 23:58 ` [PATCH] mm/mglru: fix memcg protection for global proactive reclaim Andrew Morton
2026-07-24 3:47 ` Ridong Chen
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=20260723130559.2343690-1-ridong.chen@linux.dev \
--to=ridong.chen@linux.dev \
--cc=akpm@linux-foundation.org \
--cc=axelrasmussen@google.com \
--cc=baohua@kernel.org \
--cc=chenridong@xiaomi.com \
--cc=david@kernel.org \
--cc=hannes@cmpxchg.org \
--cc=kasong@tencent.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=mhocko@kernel.org \
--cc=qi.zheng@linux.dev \
--cc=shakeel.butt@linux.dev \
--cc=weixugc@google.com \
--cc=yuanchu@google.com \
--cc=yuzhao@google.com \
/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.