From: Baolin Wang <baolin.wang@linux.alibaba.com>
To: Barry Song <baohua@kernel.org>
Cc: Xiang Liu <liuxiang.277@bytedance.com>,
Andrew Morton <akpm@linux-foundation.org>,
Johannes Weiner <hannes@cmpxchg.org>,
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>,
Axel Rasmussen <axelrasmussen@google.com>,
Yuanchu Xie <yuanchu@google.com>, Wei Xu <weixugc@google.com>,
Baoquan He <baoquan.he@linux.dev>,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
Bo Zhang <zhangbo56@xiaomi.com>
Subject: Re: [RFC PATCH v2] mm: vmscan: avoid anon scanning for GFP_NOIO with low swapcache in MGLRU
Date: Thu, 22 Oct 2026 16:49:01 +0800 [thread overview]
Message-ID: <0cbd219d-f69d-4f72-aec5-43e1f2d978de@linux.alibaba.com> (raw)
In-Reply-To: <CAGsJ_4wV8A5snz-XE+5ht931=07SvCs_k4xvUCE1yphKyQd8tw@mail.gmail.com>
On 10/22/26 5:55 AM, Barry Song wrote:
> On Wed, Oct 21, 2026 at 3:28 PM Baolin Wang
> <baolin.wang@linux.alibaba.com> wrote:
> [...]
>
>>> static bool lruvec_is_sizable(struct lruvec *lruvec, struct scan_control *sc)
>>> {
>>> unsigned long total;
>>> int swappiness = get_swappiness(lruvec, sc);
>>> struct mem_cgroup *memcg = lruvec_memcg(lruvec);
>>>
>>> + swappiness = get_scan_swappiness(lruvec, sc, swappiness);
>>> +
>>> total = lruvec_evictable_size(lruvec, swappiness);
>>>
>>> /* whether the size is big enough to be helpful */
>>> @@ -5249,9 +5265,10 @@ static bool try_to_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
>>> bool need_rotate = false, should_age = false;
>>> long nr_batch, nr_to_scan;
>>> int swappiness = get_swappiness(lruvec, sc);
>>> + int scan_swappiness = get_scan_swappiness(lruvec, sc, swappiness);
>>
>> IMO, 'swappiness' and 'scan_swappiness' are really confusing. Why move
>> this logic into get_swappiness()? In get_swappiness(), we already have
>> some similar logic to adjust swappiness when there is no available swap
>> space.
>>
>
> Yes. It is very confusing. we can't do that in get_swappiness() as otherwise,
> we will get cold/hot inversion due to GFP_NOIO. for a real swappiness=0,
> we allow cold/hot inversion for anon, but for GFP_NOIO, this is not the
> case.
But can_reclaim_anon_pages() doesn't only handle the GFP_NOIO case, it
also covers the swap space limitation scenario. The latter is what
concerns me more.
If we're only talking about the GFP_NOIO case, I'd agree with your
concern. However, we could introduce a helper to force anon aging and
add comments explaining why we need this. That would look more
maintainable than 2 confusing swappiness variables, no?
Just my 2 cents.
Something like below (untested):
diff --git a/mm/vmscan.c b/mm/vmscan.c
index daa7e37c2236..7c1d26e6b9d7 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2890,7 +2890,7 @@ static int get_swappiness(struct lruvec *lruvec,
struct scan_control *sc)
if (swappiness == SWAPPINESS_ANON_ONLY)
return swappiness;
- if (!sc->may_swap)
+ if (!sc->may_swap || !(sc->gfp_mask & __GFP_IO))
return 0;
if (!can_demote(pgdat->node_id, sc, memcg) &&
@@ -4049,7 +4049,7 @@ static inline void flush_lru_batch(struct
list_head *head, struct list_head **ba
*batch_end = NULL;
}
-static bool inc_min_seq(struct lruvec *lruvec, int type, int swappiness)
+static bool inc_min_seq(struct lruvec *lruvec, int type, int
swappiness, bool force_anon_aging)
{
int zone;
int remaining = MAX_LRU_BATCH;
@@ -4063,7 +4063,7 @@ static bool inc_min_seq(struct lruvec *lruvec, int
type, int swappiness)
goto done;
/* For anon type, skip the check if swappiness is zero (file
only) */
- if (!type && !swappiness)
+ if (!type && !swappiness && !force_anon_aging)
goto done;
VM_WARN_ON_ONCE(get_nr_gens(lruvec, type) != MAX_NR_GENS);
@@ -4183,7 +4183,20 @@ static void try_to_inc_min_seq(struct lruvec
*lruvec, int swappiness)
}
}
-static bool inc_max_seq(struct lruvec *lruvec, unsigned long seq, int
swappiness)
+static bool is_force_anon_aging(struct scan_control *sc, struct lruvec
*lruvec,
+ int swappiness)
+{
+ if (swappiness || (sc->gfp_mask & __GFP_IO))
+ return false;
+
+ /*
+ * Explain why we neeed to force increase anon min seq.
+ * xxxxxx
+ */
+ return swappiness != sc_swappiness(sc, lruvec_memcg(lruvec));
+}
+
+static bool inc_max_seq(struct lruvec *lruvec, unsigned long seq, int
swappiness, bool force_anon_aging)
{
bool success;
int prev, next;
@@ -4205,7 +4218,7 @@ static bool inc_max_seq(struct lruvec *lruvec,
unsigned long seq, int swappiness
if (get_nr_gens(lruvec, type) != MAX_NR_GENS)
continue;
- if (inc_min_seq(lruvec, type, swappiness))
+ if (inc_min_seq(lruvec, type, swappiness, force_anon_aging))
continue;
lruvec_unlock_irq(lruvec);
@@ -4249,7 +4262,7 @@ static bool inc_max_seq(struct lruvec *lruvec,
unsigned long seq, int swappiness
}
static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long seq,
- int swappiness, bool force_scan)
+ int swappiness, bool force_scan, bool
force_anon_aging)
{
bool success;
struct lru_gen_mm_walk *walk;
@@ -4260,7 +4273,7 @@ static bool try_to_inc_max_seq(struct lruvec
*lruvec, unsigned long seq,
VM_WARN_ON_ONCE(seq > READ_ONCE(lrugen->max_seq));
if (!mm_state)
- return inc_max_seq(lruvec, seq, swappiness);
+ return inc_max_seq(lruvec, seq, swappiness,
force_anon_aging);
/* see the comment in iterate_mm_list() */
if (seq <= READ_ONCE(mm_state->seq))
@@ -4295,7 +4308,7 @@ static bool try_to_inc_max_seq(struct lruvec
*lruvec, unsigned long seq,
} while (mm);
done:
if (success) {
- success = inc_max_seq(lruvec, seq, swappiness);
+ success = inc_max_seq(lruvec, seq, swappiness,
force_anon_aging);
WARN_ON_ONCE(!success);
}
@@ -5262,7 +5275,9 @@ static bool try_to_shrink_lruvec(struct lruvec
*lruvec, struct scan_control *sc)
}
if (should_run_aging(lruvec, max_seq, sc, swappiness)) {
- if (try_to_inc_max_seq(lruvec, max_seq,
swappiness, false))
+ bool force_anon_aging = is_force_anon_aging(sc,
lruvec, swappiness);
+
+ if (try_to_inc_max_seq(lruvec, max_seq,
swappiness, false, force_anon_aging))
need_rotate = true;
should_age = true;
}
next prev parent reply other threads:[~2026-10-22 8:49 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-20 15:18 Xiang Liu
2026-10-21 7:28 ` Baolin Wang
2026-10-21 21:55 ` Barry Song
2026-10-22 8:49 ` Baolin Wang [this message]
2026-10-22 10:27 ` 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=0cbd219d-f69d-4f72-aec5-43e1f2d978de@linux.alibaba.com \
--to=baolin.wang@linux.alibaba.com \
--cc=akpm@linux-foundation.org \
--cc=axelrasmussen@google.com \
--cc=baohua@kernel.org \
--cc=baoquan.he@linux.dev \
--cc=david@kernel.org \
--cc=hannes@cmpxchg.org \
--cc=kasong@tencent.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=liuxiang.277@bytedance.com \
--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=zhangbo56@xiaomi.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®