All of lore.kernel.org
 help / color / mirror / Atom feed
From: Prakash Gupta <prakash.gupta@oss.qualcomm.com>
To: Johannes Weiner <hannes@cmpxchg.org>,
	Michal Hocko <mhocko@kernel.org>,
	Roman Gushchin <roman.gushchin@linux.dev>,
	Shakeel Butt <shakeel.butt@linux.dev>,
	Muchun Song <muchun.song@linux.dev>,
	Andrew Morton <akpm@linux-foundation.org>,
	Kefeng Wang <wangkefeng.wang@huawei.com>,
	"Matthew Wilcox (Oracle)" <willy@infradead.org>
Cc: linux-arm-msm@vger.kernel.org, cgroups@vger.kernel.org,
	linux-mm@kvack.org, linux-kernel@vger.kernel.org,
	stable@vger.kernel.org,
	Prakash Gupta <prakash.gupta@oss.qualcomm.com>
Subject: [PATCH] mm/memcg: fix NULL nodeinfo[] dereference on late-onlined nodes
Date: Mon, 10 Aug 2026 11:16:30 +0530	[thread overview]
Message-ID: <20260810-memcg-nodeinfo-null-guard-v1-1-77a73204d63a@oss.qualcomm.com> (raw)

memcg->nodeinfo[] entries are allocated only for nodes present at
css_alloc time. When a node is onlined after a memcg is created its
nodeinfo[] slot remains NULL. Two call sites dereference these slots
unconditionally:

lruvec_stat_mod_folio() calls mem_cgroup_lruvec() which reads
memcg->nodeinfo[pgdat->node_id] without a NULL check. On a system
where a node is onlined after the memcg is created, any folio stat
update for that node crashes with a NULL pointer dereference:

  Unable to handle kernel paging request at virtual address ffffffbebf7e1908
  pc : lruvec_stat_mod_folio+0xf0/0x444   [6.18.21-android17-5]
  lr : lruvec_stat_mod_folio+0x88/0x444
  Call trace:
   lruvec_stat_mod_folio+0xf0/0x444
   folio_add_new_anon_rmap+0xac/0x2b8
   do_wp_page+0x768/0xc80
   handle_mm_fault+0x37c/0x8c4
   do_page_fault+0x140/0xa1c
   do_mem_abort+0x54/0x74
   el0_da+0x48/0x8c
   el0t_64_sync_handler+0x20/0x130
   el0t_64_sync+0x1c4/0x1c8

__invalidate_reclaim_iterators() iterates for_each_node() and reads
from->nodeinfo[nid]->iter without checking for NULL. for_each_node()
visits all possible nodes, so this is reachable whenever a node is
onlined after the memcg was created.

Fix lruvec_stat_mod_folio() by checking nodeinfo[pgdat->node_id]
directly and falling back to mod_node_page_state() when NULL, mirroring
the existing !memcg early-return path. The fallback must not go through
mod_lruvec_state() since that calls mod_memcg_lruvec_state() which uses
container_of() to recover the mem_cgroup_per_node from the lruvec
pointer; passing &pgdat->__lruvec there produces a garbage pointer.
When nodeinfo[nid] is NULL the memcg has no per-node accounting
structure for that node, so node-level accounting is correct.

Fix __invalidate_reclaim_iterators() by skipping NULL nodeinfo[] slots.

Also switch lruvec_stat_mod_folio() to folio_memcg_check() which uses
READ_ONCE() to safely read folio->memcg_data in an unlocked context.

Fixes: 6c77b607ee26 ("mm: kill lock|unlock_page_memcg()")
Cc: stable@vger.kernel.org
Assisted-by: pi:claude-sonnet-4-5
Signed-off-by: Prakash Gupta <prakash.gupta@oss.qualcomm.com>
---
 mm/memcontrol.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 6dc4888a90f3..2a6f02956b89 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -977,11 +977,12 @@ void lruvec_stat_mod_folio(struct folio *folio, enum node_stat_item idx,
 			     int val)
 {
 	struct mem_cgroup *memcg;
+	struct mem_cgroup_per_node *mz;
 	pg_data_t *pgdat = folio_pgdat(folio);
 	struct lruvec *lruvec;
 
 	rcu_read_lock();
-	memcg = folio_memcg(folio);
+	memcg = folio_memcg_check(folio);
 	/* Untracked pages have no memcg, no lruvec. Update only the node */
 	if (!memcg) {
 		rcu_read_unlock();
@@ -989,7 +990,18 @@ void lruvec_stat_mod_folio(struct folio *folio, enum node_stat_item idx,
 		return;
 	}
 
-	lruvec = mem_cgroup_lruvec(memcg, pgdat);
+	mz = memcg->nodeinfo[pgdat->node_id];
+	if (unlikely(!mz)) {
+		/*
+		 * nodeinfo[nid] is NULL when a node is onlined after the
+		 * memcg was created. Fall back to node-level accounting.
+		 */
+		rcu_read_unlock();
+		mod_node_page_state(pgdat, idx, val);
+		return;
+	}
+
+	lruvec = &mz->lruvec;
 	mod_lruvec_state(lruvec, idx, val);
 	rcu_read_unlock();
 }
@@ -1320,6 +1332,8 @@ static void __invalidate_reclaim_iterators(struct mem_cgroup *from,
 
 	for_each_node(nid) {
 		mz = from->nodeinfo[nid];
+		if (!mz)
+			continue;
 		iter = &mz->iter;
 		cmpxchg(&iter->position, dead_memcg, NULL);
 	}

---
base-commit: 075b74841bd0065a3bda3440873c747938e69b68
change-id: 20260808-memcg-nodeinfo-null-guard-dce5f63a2349

Best regards,
-- 
Prakash Gupta <prakash.gupta@oss.qualcomm.com>


             reply	other threads:[~2026-08-10  5:46 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-10  5:46 Prakash Gupta [this message]
2026-08-10  7:58 ` [PATCH] mm/memcg: fix NULL nodeinfo[] dereference on late-onlined nodes Muchun Song
2026-08-11  5:16   ` Prakash Gupta
2026-08-11  6:19     ` Muchun Song
2026-08-26  6:30 ` kernel test robot

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=20260810-memcg-nodeinfo-null-guard-v1-1-77a73204d63a@oss.qualcomm.com \
    --to=prakash.gupta@oss.qualcomm.com \
    --cc=akpm@linux-foundation.org \
    --cc=cgroups@vger.kernel.org \
    --cc=hannes@cmpxchg.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mhocko@kernel.org \
    --cc=muchun.song@linux.dev \
    --cc=roman.gushchin@linux.dev \
    --cc=shakeel.butt@linux.dev \
    --cc=stable@vger.kernel.org \
    --cc=wangkefeng.wang@huawei.com \
    --cc=willy@infradead.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.