Re: [PATCH v2 1/2] mm: multi-gen LRU: fix NULL lruvec->pgdat deref with memcg disabled on cmdline
From: Siddharth Chintamaneni
Date: Mon Oct 19 2026 - 16:40:18 EST
On Sun, 18 Oct 2026 at 14:05, Barry Song <baohua@xxxxxxxxxx> wrote:
>
> On Sat, Oct 17, 2026 at 1:09 PM Siddharth Chintamaneni
> <sidchintamaneni@xxxxxxxxx> wrote:
> >
> > When CONFIG_MEMCG=y, lruvec_pgdat() returns lruvec->pgdat, which for the
> > per-node pgdat->__lruvec is left NULL by lruvec_init() and only filled in
> > lazily by mem_cgroup_lruvec(). Normally that happens early, e.g. on the
> > first folio_add_lru().
> >
> > With cgroup_disable=memory, lru_gen_shrink_node() passes &pgdat->__lruvec
> > directly to shrink_one(). If direct reclaim runs before anything has
> > called mem_cgroup_lruvec() for the node, which can happen during early
> > boot under memory pressure (e.g. a kdump kernel), get_swappiness() ends
> > up dereferencing a NULL pgdat:
> >
> > Unable to handle kernel NULL pointer dereference at virtual address 0000000000005040
> > pc : get_swappiness+0x68/0xb0
> > lr : try_to_shrink_lruvec+0x54/0x2c0
> > Call trace:
> > get_swappiness+0x68/0xb0 (P)
> > try_to_shrink_lruvec+0x54/0x2c0
> > shrink_one+0x8c/0x240
> > shrink_node+0xc6c/0xe08
> > do_try_to_free_pages+0xdc/0x570
> > try_to_free_pages+0x124/0x278
> > __alloc_frozen_pages_noprof+0x6e8/0xf78
> > alloc_pages_mpol+0xc4/0x1c0
> > alloc_frozen_pages_noprof+0x54/0xe8
> > alloc_pages_noprof+0x1c/0x40
> > atomic_pool_expand+0x98/0x300
> > __dma_atomic_pool_init+0x58/0xd8
> > dma_atomic_pool_init+0x154/0x170
> > do_one_initcall+0x64/0x350
> > kernel_init_freeable+0x214/0x430
> > kernel_init+0x2c/0x208
> > ret_from_fork+0x10/0x20
> >
> > The classic LRU path and MGLRU before per-node lru_gen_folio lists
> > obtained the lruvec through mem_cgroup_lruvec(), which sets
> > lruvec->pgdat.
> >
> > The above was hit on an arm64 kdump kernel (6.18-based) booted with
> > cgroup_disable=memory nr_cpus=4. It also reproduces on mainline on an
> > arm64 VM with CONFIG_ARM64_64K_PAGES=y, CONFIG_MEMCG=y,
> > CONFIG_LRU_GEN_ENABLED=y and:
> >
> > mem=160M nr_cpus=4 coherent_pool=512M cgroup_disable=memory
> >
> > These options only serve to force direct reclaim early in boot; with
> > 160M the boot eventually ends in OOM regardless. On mainline the first
> > LRU reclaim happens while unpacking the initramfs, and faults the same
> > way:
> >
> > Unable to handle kernel NULL pointer dereference at virtual address 0000000000005040
> > pc : get_swappiness+0xd4/0x150
> > Call trace:
> > get_swappiness+0xd4/0x150 (P)
> > try_to_shrink_lruvec+0x44/0x2b8
> > shrink_one+0x80/0x1a0
> > shrink_node+0xd98/0xea8
> > do_try_to_free_pages+0xf4/0x4b0
> > try_to_free_pages+0x110/0x360
> > __alloc_frozen_pages_noprof+0x8b0/0x1718
> > ...
> > __filemap_get_folio_mpol+0x2ac/0x548
> > simple_write_begin+0x44/0xf8
> > page_symlink+0x178/0x198
> > ...
> > do_populate_rootfs+0x13c/0x200
> >
>
> So this happens before any folios are added to the LRU and before
> the userspace init process starts?
>
Yes!
> > Fixes: e4dde56cd208 ("mm: multi-gen LRU: per-node lru_gen_folio lists")
> > Cc: stable@xxxxxxxxxxxxxxx # 6.3+
> > Assisted-by: LLM
> > Signed-off-by: Siddharth Chintamaneni <sidchintamaneni@xxxxxxxxx>
> > Signed-off-by: Hardik Garg <hargar@xxxxxxxxxxxxxxxxxxx>
> > ---
> > mm/vmscan.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/mm/vmscan.c b/mm/vmscan.c
> > index f11491ee9ed5..0c57e4f1eb15 100644
> > --- a/mm/vmscan.c
> > +++ b/mm/vmscan.c
> > @@ -5253,7 +5253,7 @@ static void lru_gen_shrink_node(struct pglist_data *pgdat, struct scan_control *
> > sc->nr_reclaimed = 0;
> >
> > if (mem_cgroup_disabled())
> > - shrink_one(&pgdat->__lruvec, sc);
> > + shrink_one(mem_cgroup_lruvec(NULL, pgdat), sc);
>
> What's a bit weird is that even if we fix this here, with an empty
> lruvec, we still won't be able to reclaim a single page. But it's
> hard to see where we could break out early, right?
>
I am not really sure about simple bailout logic. Please let me know if
anyone have any thoughts.
> > else
> > shrink_many(pgdat, sc);
>
> Best Regards
> Barry