Re: [PATCH v2 1/2] mm: multi-gen LRU: use mem_cgroup_lruvec() in get_lruvec()
From: Andrew Morton
Date: Mon Nov 02 2026 - 18:41:31 EST
On Tue, 3 Nov 2026 06:51:19 +0800 Barry Song <baohua@xxxxxxxxxx> wrote:
> On Tue, Oct 27, 2026 at 4:23 AM Siddharth Chintamaneni
> <sidchintamaneni@xxxxxxxxx> wrote:
> >
> > Andrew Morton noted that get_lruvec() has the same pattern as
> > lru_gen_shrink_node(): when memcg is disabled on the command line
> > (cgroup_disable=memory), it returns &pgdat->__lruvec directly instead of
> > going through mem_cgroup_lruvec(), which initializes lruvec->pgdat.
> >
> > In practice all callers of get_lruvec() run after kswapd_init() has
> > already initialized pgdat->__lruvec.pgdat on every N_MEMORY node, so
> > this is not a runtime bug. Have get_lruvec() delegate to
> > mem_cgroup_lruvec() directly.
>
> Somehow, I feel this changelog is a bit weird. The earlier
> description doesn't really justify the final sentence:
> "Have get_lruvec() delegate to mem_cgroup_lruvec() directly."
>
> Can we change it to the below?
>
> The patch was initially developed to address a possible NULL
> reference [1].
>
> Andrew Morton reported that get_lruvec() has the same problem as
> lru_gen_shrink_node(): when memcg is disabled on the command line
> (cgroup_disable=memory), it returns &pgdat->__lruvec directly and so
> bypasses the initialization of lruvec->pgdat. The MGLRU debugfs
> interface calls get_lruvec(), then dereferences the pgdat pointer in
> lru_gen_seq_show() and other paths, so these can hit the same NULL
> dereference.
>
> In practice, we found that this cannot happen, as all callers of
> get_lruvec() run after kswapd_init() has initialized
> pgdat->__lruvec.pgdat on every N_MEMORY node. Therefore, this
> is not a runtime bug.
>
> However, it would still be good to clean up get_lruvec() by
> removing the MGLRU-specific code and having it delegate
> directly to mem_cgroup_lruvec().
>
> [1] https://lore.kernel.org/linux-mm/20261017050928.128582-2-sidchintamaneni@xxxxxxxxx/
Thanks, I locally made that change.
From: Siddharth Chintamaneni <sidchintamaneni@xxxxxxxxx>
Subject: mm: multi-gen LRU: use mem_cgroup_lruvec() in get_lruvec()
Date: Mon, 26 Oct 2026 20:23:12 +0000
Patch series "mm: multi-gen LRU: replace get_lruvec() with
mem_cgroup_lruvec()", v2.
This series cleans up MGLRU's get_lruvec() helper in mm/vmscan.c.
Patch 1 updates get_lruvec() to delegate to mem_cgroup_lruvec() rather
than returning &pgdat->__lruvec directly when memcg is disabled on the
kernel command line.
Patch 2 removes get_lruvec() completely and replaces all 15 call sites
with mem_cgroup_lruvec().
This patch (of 2):
The patch was initially developed to address a possible NULL reference
[1].
Andrew Morton reported that get_lruvec() has the same problem as
lru_gen_shrink_node(): when memcg is disabled on the command line
(cgroup_disable=memory), it returns &pgdat->__lruvec directly and so
bypasses the initialization of lruvec->pgdat. The MGLRU debugfs interface
calls get_lruvec(), then dereferences the pgdat pointer in
lru_gen_seq_show() and other paths, so these can hit the same NULL
dereference.
In practice, we found that this cannot happen, as all callers of
get_lruvec() run after kswapd_init() has initialized pgdat->__lruvec.pgdat
on every N_MEMORY node. Therefore, this is not a runtime bug.
However, it would still be good to clean up get_lruvec() by removing the
MGLRU-specific code and having it delegate directly to
mem_cgroup_lruvec().
Link: https://lore.kernel.org/20261026202313.63122-1-sidchintamaneni@xxxxxxxxx
Link: https://lore.kernel.org/20261026202313.63122-2-sidchintamaneni@xxxxxxxxx
Link: https://lore.kernel.org/linux-mm/20261017050928.128582-2-sidchintamaneni@xxxxxxxxx/ [1]
Signed-off-by: Siddharth Chintamaneni <sidchintamaneni@xxxxxxxxx>
Signed-off-by: Hardik Garg <hargar@xxxxxxxxxxxxxxxxxxx>
Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
Reviewed-by: Baolin Wang <baolin.wang@xxxxxxxxxxxxxxxxx>
Reviewed-by: Barry Song <baohua@xxxxxxxxxx>
Cc: Johannes Weiner <hannes@xxxxxxxxxxx>
Cc: David Hildenbrand <david@xxxxxxxxxx>
Cc: Michal Hocko <mhocko@xxxxxxxxxx>
Cc: Qi Zheng <qi.zheng@xxxxxxxxx>
Cc: Shakeel Butt <shakeel.butt@xxxxxxxxx>
Cc: Lorenzo Stoakes <ljs@xxxxxxxxxx>
Cc: Kairui Song <kasong@xxxxxxxxxxx>
Cc: Axel Rasmussen <axelrasmussen@xxxxxxxxxx>
Cc: Yuanchu Xie <yuanchu@xxxxxxxxxx>
Cc: Wei Xu <weixugc@xxxxxxxxxx>
Cc: Baoquan He <baoquan.he@xxxxxxxxx>
Cc: Yu Zhao <yuzhao@xxxxxxxxxx>
Cc: <apais@xxxxxxxxxxxxx>
Cc: <rlmenge@xxxxxxxxx>
---
mm/vmscan.c | 15 ++-------------
1 file changed, 2 insertions(+), 13 deletions(-)
--- a/mm/vmscan.c~mm-multi-gen-lru-use-mem_cgroup_lruvec-in-get_lruvec
+++ a/mm/vmscan.c
@@ -2866,20 +2866,9 @@ static struct lruvec *get_lruvec(struct
{
struct pglist_data *pgdat = NODE_DATA(nid);
-#ifdef CONFIG_MEMCG
- if (memcg) {
- struct lruvec *lruvec = &memcg->nodeinfo[nid]->lruvec;
+ VM_WARN_ON_ONCE(!memcg && !mem_cgroup_disabled());
- /* see the comment in mem_cgroup_lruvec() */
- if (!lruvec->pgdat)
- lruvec->pgdat = pgdat;
-
- return lruvec;
- }
-#endif
- VM_WARN_ON_ONCE(!mem_cgroup_disabled());
-
- return &pgdat->__lruvec;
+ return mem_cgroup_lruvec(memcg, pgdat);
}
static int get_swappiness(struct lruvec *lruvec, struct scan_control *sc)
_