[PATCH 2/2] mm/page_owner: also check PageTail before reading memcg_data

From: Daejun Park via B4 Relay

Date: Wed Nov 04 2026 - 05:03:53 EST


From: Daejun Park <daejun7.park@xxxxxxxxxxx>

print_page_owner_memcg() loads memcg_data before it tests PageTail().
In the first tail page, memcg_data holds the folio's _nr_pages. A split
can make the page a folio between the two loads. The stale _nr_pages
then passes the PageTail() test and is used as an objcg pointer.

__split_folio_to_order() stores memcg_data before the smp_wmb() that
precedes clear_compound_head(). Also test PageTail() before the load,
with a paired smp_rmb(). Keep the test after the load for a page that
becomes a tail in between.

Fixes: 4996fc547f5b ("mm: let _folio_nr_pages overlay memcg_data in first tail page")
Signed-off-by: Daejun Park <daejun7.park@xxxxxxxxxxx>
---
Needs patch 1 for the store order. Found by reading the code, not
reproduced. The page_owner oops seen with a delay after
clear_compound_head() is the window patch 1 closes.
---
mm/page_owner.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/mm/page_owner.c b/mm/page_owner.c
index cfc31c92d7..058d4dec84 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -564,6 +564,13 @@ static inline int print_page_owner_memcg(char *kbuf, size_t count, int ret,
char name[80];

rcu_read_lock();
+ if (PageTail(page))
+ goto out_unlock;
+ /*
+ * Order the memcg_data load after the PageTail() load. Pairs with
+ * smp_wmb() in __split_folio_to_order().
+ */
+ smp_rmb();
memcg_data = READ_ONCE(page->memcg_data);
if (!memcg_data || PageTail(page))
goto out_unlock;

--
2.43.0