Re: kernel NULL pointer dereference in drain_obj_stock during ext4 e4defrag

From: Johannes Weiner

Date: Wed Jul 08 2026 - 14:42:06 EST


Hello Michael,

On Tue, Jul 07, 2026 at 06:51:14PM -0500, Michael Hicklen wrote:
> Kernel: 7.1.2-arch3-1
> Arch: x86_64
> Hardware: MSI MS-7C95 / PRO B550M-VC WIFI
> CPU: AMD (kvm_amd loaded)
>
> Workload:
>
> 4 concurrent e4defrag processes operating on 4 separate ext4
> filesystems on 4 separate HDDs.
>
> The crash happens during memory reclaim while ext4_move_extents() is running.
>
> First oops:
>
> BUG: kernel NULL pointer dereference, address: 0000000000000676
> #PF: supervisor read access in kernel mode
>
> RIP: drain_obj_stock+0x175/0x310

Thanks for the report. The trace and register state suggests that we
have the stock pointing to a dead objcg. Through this mess of
container_of(), you basically have to read the lines in reverse:

drain_obj_stock()
mod_objcg_mlstate(old = stock->cached_objcg, stock->cached_pgdat, ...)
rcu_read_lock()
memcg = obj_cgroup_memcg(old) // objcg->memcg: stale value
lruvec = mem_cgroup_lruvec(memcg, pgdat) // memcg->nodeinfo[nid]: stale value
mod_memcg_lruvec_state(lruvec, ...)
pn = container_of(lruvec, ...)
memcg = pn->memcg // freed pn, first 8 bytes now contain 6
pn = memcg->nodeinfo[pgdat->node_id] // <<< faults: 6 + 0x670 = 0x676

Michael, do you have the full dmesg available from this machine? The
oops you included already include taint flags for previous crashes and
warnings.

There is an interleaved Code: block (twice) that disassembles to what
looks like an obj_cgroup_get() encountering a percpu_count_ptr of 0,
which further suggests use-after-free of the objcg.