From: "Barry Song (Xiaomi)" <baohua@kernel.org>
To: ryncsn@gmail.com
Cc: akpm@linux-foundation.org, axelrasmussen@google.com,
baohua@kernel.org, baolin.wang@linux.alibaba.com,
baoquan.he@linux.dev, hannes@cmpxchg.org, hui.zhu@linux.dev,
kunwu.chan@gmail.com, liam@infradead.org, lianux.mm@gmail.com,
linux-mm@kvack.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,
sashiko-bot@kernel.org, sashiko-reviews@lists.linux.dev,
shakeel.butt@linux.dev, sidchintamaneni@gmail.com,
surenb@google.com, wangzicheng@honor.com, weixugc@google.com,
yuanchu@google.com, zhangbo56@xiaomi.com, zhuhui@kylinos.cn
Subject: Re: [PATCH v9 11/16] mm/mglru: Run aging when one type is drained
Date: Mon, 16 Nov 2026 06:00:07 +0800 [thread overview]
Message-ID: <20261115220007.89063-1-baohua@kernel.org> (raw)
In-Reply-To: <CAMgjq7DiH1SJCR0DMwf=16cxXO2PZcjSuD41sO7_2hOcXuPUQQ@mail.gmail.com>
On Mon, Nov 16, 2026 at 2:07 AM Kairui Song <ryncsn@gmail.com> wrote:
>
> On Sun, Nov 15, 2026 at 5:44 AM Barry Song (Xiaomi) <baohua@kernel.org> wrote:
> >
> > On Sun, Nov 15, 2026 at 4:50 AM <sashiko-bot@kernel.org> wrote:
> > >
> > > Thank you for your contribution! Sashiko AI review found 2 potential
> > > issues to consider:
> > > - [Medium] mm/mglru: scan_folios() scans seq below min_seq at
> > > DEF_PRIORITY
> >
> > I guess reparenting could be a corner case where it's difficult to
> > properly preserve the cold/hot ordering.
>
> I think we don't need to care about hotness for reparenting, MGLRU's
> reparent just forcefully squashes the old gen into the parent's gen,
> and most likely in the wrong window order, the hotness info is already
> severely skewed; there's no way to cover that until we run the aging.
> In fact I think we should patch reparent instead, maybe later,
> squashing everything into the oldest generation seems a more
> reasonable solution for reparenting?
Right. The current reparenting behavior is already quite odd,
given that generation numbers wrap around. A larger generation
number doesn't necessarily mean a younger or older generation,
so the ordering can already be completely disrupted.
static void __lru_gen_reparent_memcg(struct lruvec *child_lruvec, struct lruvec *parent_lruvec,
int zone, int type)
{
child_lrugen = &child_lruvec->lrugen;
parent_lrugen = &parent_lruvec->lrugen;
for (gen = 0; gen < MAX_NR_GENS; gen++) {
long nr_pages = child_lrugen->nr_pages[gen][type][zone];
int child_lru_active = lru_gen_is_active(child_lruvec, gen) ? LRU_ACTIVE : 0;
int parent_lru_active = lru_gen_is_active(parent_lruvec, gen) ? LRU_ACTIVE : 0;
/* Assuming that child pages are colder than parent pages */
list_splice_tail_init(&child_lrugen->folios[gen][type][zone],
&parent_lrugen->folios[gen][type][zone]);
...
}
}
I think it makes perfect sense to simplify the code by moving
all child folios to the parent's min_seq, especially since
there's already a comment saying:
"Assuming that child pages are colder than parent pages"
And I think the current active/inactive counting is absolutely
wrong for reparenting:
static inline bool lru_gen_is_active(const struct lruvec *lruvec, int gen)
{
unsigned long max_seq = lruvec->lrugen.max_seq;
VM_WARN_ON_ONCE(gen >= MAX_NR_GENS);
/* see the comment on MIN_NR_GENS */
return gen == lru_gen_from_seq(max_seq) || gen == lru_gen_from_seq(max_seq - 1);
}
Considering that the parent memcg has only two generations,
some child folios may end up in lru_gen_from_seq(max_seq + 1),
which is also lru_gen_from_seq(min_seq - 2), while others may
end up in lru_gen_from_seq(max_seq + 2), which is also
lru_gen_from_seq(min_seq - 1), due to the wraparound.
In that case, wouldn't max_seq and max_seq - 1 effectively
represent "inactive", while lru_gen_from_seq(max_seq + 1)
and lru_gen_from_seq(max_seq + 2) represent "active"?
This makes your idea of moving all child folios to the
parent memcg's oldest generation even more compelling!
I drafted the following code based on your idea. It's unrelated
to this series and would be a separate change:
(also I found another bug, __update_lru_size() is only called
while parent/child active status is different - this will
make both parent/child lru statistics wrong, so i dropped
it)
diff --git a/mm/vmscan.c b/mm/vmscan.c
index a5b8244d4768..582bce575cec 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -4620,28 +4620,27 @@ static void __lru_gen_reparent_memcg(struct lruvec *child_lruvec, struct lruvec
{
struct lru_gen_folio *child_lrugen, *parent_lrugen;
enum lru_list lru = type * LRU_INACTIVE_FILE;
- int gen;
+ int gen, parent_gen;
child_lrugen = &child_lruvec->lrugen;
parent_lrugen = &parent_lruvec->lrugen;
+ parent_gen = lru_gen_from_seq(READ_ONCE(parent_lrugen->min_seq[type]));
+ int parent_lru_active = lru_gen_is_active(parent_lruvec, parent_gen) ? LRU_ACTIVE : 0;
for (gen = 0; gen < MAX_NR_GENS; gen++) {
long nr_pages = child_lrugen->nr_pages[gen][type][zone];
int child_lru_active = lru_gen_is_active(child_lruvec, gen) ? LRU_ACTIVE : 0;
- int parent_lru_active = lru_gen_is_active(parent_lruvec, gen) ? LRU_ACTIVE : 0;
/* Assuming that child pages are colder than parent pages */
list_splice_tail_init(&child_lrugen->folios[gen][type][zone],
- &parent_lrugen->folios[gen][type][zone]);
+ &parent_lrugen->folios[parent_gen][type][zone]);
WRITE_ONCE(child_lrugen->nr_pages[gen][type][zone], 0);
WRITE_ONCE(parent_lrugen->nr_pages[gen][type][zone],
- parent_lrugen->nr_pages[gen][type][zone] + nr_pages);
+ parent_lrugen->nr_pages[parent_gen][type][zone] + nr_pages);
- if (lru_gen_is_active(child_lruvec, gen) != lru_gen_is_active(parent_lruvec, gen)) {
- __update_lru_size(child_lruvec, lru + child_lru_active, zone, -nr_pages);
- __update_lru_size(parent_lruvec, lru + parent_lru_active, zone, nr_pages);
- }
+ __update_lru_size(child_lruvec, lru + child_lru_active, zone, -nr_pages);
+ __update_lru_size(parent_lruvec, lru + parent_lru_active, zone, nr_pages);
}
}
>
> And if the child's old generation was squashed into an out-of-window
> generation, these out-of-window cold folios will get evicted much
> later than the hot folios. In that case we even somehow "fixed" that
> by this patch :P, as long there is no leak, I think it's hard to
> define what is the right behavior.
Yes, agreed.
Another thing we could do is add the change I mentioned in my
reply to Sashiko [1], which Andrew has already picked up.
@@ -4788,6 +4788,9 @@ static int scan_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
seq = lrugen->max_seq;
seq = lruvec_populated_min_seq(lruvec, type, sc->reclaim_idx + 1, seq);
+ if (seq < lrugen->min_seq[type])
+ return 0;
+
This would avoid iterating over each zone's list just to check
whether it is empty. That's the case most of the time, except
for corner cases involving reparenting.
[1] https://lore.kernel.org/linux-mm/20261114214438.70148-1-baohua@kernel.org/
Thanks
Barry
next prev parent reply other threads:[~2026-11-15 22:00 UTC|newest]
Thread overview: 26+ 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-15 15:15 ` Kairui Song
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-15 15:54 ` Kairui Song
2026-11-14 20:07 ` [PATCH v9 11/16] mm/mglru: Run aging when one type is drained Barry Song (Xiaomi)
2026-11-14 20:50 ` sashiko-bot
2026-11-14 21:44 ` Barry Song (Xiaomi)
2026-11-15 18:07 ` Kairui Song
2026-11-15 22:00 ` Barry Song (Xiaomi) [this message]
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-15 15:52 ` Kairui Song
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)
2026-11-14 22:09 ` [PATCH v9 00/16] mm: mglru: fix swappiness behavior Andrew Morton
2026-11-15 1:10 ` Barry 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=20261115220007.89063-1-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=kunwu.chan@gmail.com \
--cc=liam@infradead.org \
--cc=lianux.mm@gmail.com \
--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=sashiko-bot@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--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