From: "Gregory Price (Meta)" <gourry@gourry.net>
To: linux-mm@kvack.org
Cc: linux-kernel@vger.kernel.org, linux-cxl@vger.kernel.org,
kernel-team@meta.com, akpm@linux-foundation.org,
vbabka@kernel.org, surenb@google.com, mhocko@suse.com,
brendan.jackman@linux.dev, hannes@cmpxchg.org, ziy@nvidia.com,
linmiaohe@huawei.com, nao.horiguchi@gmail.com, david@kernel.org,
ljs@kernel.org, liam@infradead.org, rppt@kernel.org,
osalvador@suse.de, muchun.song@linux.dev, iamjoonsoo.kim@lge.com,
anshuman.khandual@arm.com, stable@vger.kernel.org
Subject: [PATCH 2/6] mm/page_owner: hold off memory offline while a page is read
Date: Tue, 27 Oct 2026 00:22:00 -0400 [thread overview]
Message-ID: <20261027042204.3741307-3-gourry@gourry.net> (raw)
In-Reply-To: <20261027042204.3741307-1-gourry@gourry.net>
Reading /sys/kernel/debug/page_owner while memory is removed can oops.
read_page_owner() checks a pfn with pfn_valid(), and print_page_owner()
can sleep in kmalloc() before it reads the struct page:
CPU 1 (read page_owner) CPU 2 (remove the memory block)
pfn_valid(pfn)
page = pfn_to_page(pfn)
page_ext_get()
page_ext_put()
print_page_owner()
kmalloc()
offline_pages()
remove_pfn_range_from_zone()
arch_remove_memory()
frees the vmemmap
get_pageblock_migratetype(page)
BUG: unable to handle page fault for address: ffd4000006000000
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
Oops: Oops: 0000 [#1] SMP KASAN
RIP: 0010:__get_pfnblock_flags_mask+0x3e/0x2b0
Call Trace:
<TASK>
get_pfnblock_migratetype+0xf/0x20
read_page_owner+0x629/0xf00
full_proxy_read+0x102/0x190
vfs_read+0x153/0xcd0
ksys_read+0xe4/0x1b0
do_syscall_64+0xbd/0x630
entry_SYSCALL_64_after_hwframe+0x4b/0x53
Offline alone faults the same way on DEBUG_VM kernels. The page_ext is
safe; offline_page_ext() frees it after an RCU grace period.
Check the pfn with pfn_to_online_page() inside a pfn_walk read section,
which offline waits for, and move kmalloc() and copy_to_user() out of
it, since offline waits with the hotplug locks held. A full read of
page_owner in a 5G guest takes 1.36 s before and 1.34 s after.
With a kprobe sleeping the reader on a DIMM pfn across an offline or a
removal, base faults in 3 of 3 runs of each and this patch in none.
Fixes: 48c96a368579 ("mm/page_owner: keep track of page owners")
Cc: stable@vger.kernel.org
Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
---
mm/page_owner.c | 45 ++++++++++++++++++++++++---------------------
1 file changed, 24 insertions(+), 21 deletions(-)
diff --git a/mm/page_owner.c b/mm/page_owner.c
index cfc31c92d7657..d2c0b831fcd3b 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -13,6 +13,7 @@
#include <linux/memcontrol.h>
#include <linux/sched/clock.h>
+#include "internal.h"
#include "page_alloc.h"
/*
@@ -600,20 +601,14 @@ static inline int print_page_owner_memcg(char *kbuf, size_t count, int ret,
#endif
static ssize_t
-print_page_owner(char __user *buf, size_t count, unsigned long pfn,
+print_page_owner(char *kbuf, size_t count, unsigned long pfn,
struct page *page, struct page_owner *page_owner,
depot_stack_handle_t handle,
struct page_owner_filter_state *state)
{
int ret, pageblock_mt, page_mt;
- char *kbuf;
enum page_owner_print_mode print_mode;
- count = min_t(size_t, count, PAGE_SIZE);
- kbuf = kmalloc(count, GFP_KERNEL);
- if (!kbuf)
- return -ENOMEM;
-
print_mode = state->print_mode;
ret = scnprintf(kbuf, count,
@@ -637,14 +632,14 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn,
if (print_mode != PAGE_OWNER_PRINT_HANDLE) {
ret += stack_depot_snprint(handle, kbuf + ret, count - ret, 0);
if (ret >= count)
- goto err;
+ return -ENOMEM;
}
if (print_mode != PAGE_OWNER_PRINT_STACK) {
ret += scnprintf(kbuf + ret, count - ret, "handle: %u\n",
handle);
if (ret >= count)
- goto err;
+ return -ENOMEM;
}
if (page_owner->last_migrate_reason != MR_NEVER) {
@@ -657,17 +652,9 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn,
ret += snprintf(kbuf + ret, count - ret, "\n");
if (ret >= count)
- goto err;
-
- if (copy_to_user(buf, kbuf, ret))
- ret = -EFAULT;
+ return -ENOMEM;
- kfree(kbuf);
return ret;
-
-err:
- kfree(kbuf);
- return -ENOMEM;
}
void __dump_page_owner(const struct page *page)
@@ -734,10 +721,17 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)
struct page_owner *page_owner;
depot_stack_handle_t handle;
struct page_owner_filter_state *state = file->private_data;
+ ssize_t ret = 0;
+ char *kbuf;
if (!static_branch_unlikely(&page_owner_inited))
return -EINVAL;
+ count = min_t(size_t, count, PAGE_SIZE);
+ kbuf = kmalloc(count, GFP_KERNEL);
+ if (!kbuf)
+ return -ENOMEM;
+
page = NULL;
if (*ppos == 0)
pfn = min_low_pfn;
@@ -766,7 +760,12 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)
continue;
}
- page = pfn_to_page(pfn);
+ /* Offline waits for us before it poisons the memmap */
+ guard(pfn_walk)();
+ page = pfn_to_online_page(pfn);
+ if (!page)
+ continue;
+
if (skip_buddy_pages(&pfn, page))
continue;
@@ -825,14 +824,18 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)
page_owner_tmp = *page_owner;
page_ext_put(page_ext);
- return print_page_owner(buf, count, pfn, page,
+ ret = print_page_owner(kbuf, count, pfn, page,
&page_owner_tmp, handle, state);
+ break;
ext_put_continue:
page_ext_put(page_ext);
cond_resched();
}
- return 0;
+ if (ret > 0 && copy_to_user(buf, kbuf, ret))
+ ret = -EFAULT;
+ kfree(kbuf);
+ return ret;
}
static loff_t lseek_page_owner(struct file *file, loff_t offset, int orig)
--
2.53.0-Meta
next prev parent reply other threads:[~2026-10-27 4:22 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-27 4:21 [PATCH 0/6] mm: fix pfn walker races with memory offline Gregory Price (Meta)
2026-10-27 4:21 ` [PATCH 1/6] mm/compaction: wait for pfn walkers before poisoning offlined memmap Gregory Price (Meta)
2026-10-27 13:38 ` David Hildenbrand (Arm)
2026-10-27 4:22 ` Gregory Price (Meta) [this message]
2026-10-27 4:22 ` [PATCH 3/6] mm/memory-failure: keep the page online while handling it Gregory Price (Meta)
2026-10-27 4:22 ` [PATCH 4/6] mm/page_alloc: don't undo another isolation in alloc_contig_range Gregory Price (Meta)
2026-10-27 13:37 ` David Hildenbrand (Arm)
2026-10-27 14:06 ` Gregory Price (Meta)
2026-10-27 14:13 ` David Hildenbrand (Arm)
2026-10-27 18:53 ` Zi Yan
2026-10-27 18:58 ` David Hildenbrand (Arm)
2026-10-27 19:38 ` Gregory Price
2026-10-27 4:22 ` [PATCH 5/6] mm/page_alloc: keep the range online while alloc_contig isolates it Gregory Price (Meta)
2026-10-27 4:22 ` [PATCH 6/6] mm/hwpoison-inject: keep the page online while filtering it Gregory Price (Meta)
2026-10-27 8:57 ` [PATCH 0/6] mm: fix pfn walker races with memory offline David Hildenbrand (Arm)
2026-10-27 11:31 ` Gregory Price (Meta)
2026-10-27 12:51 ` David Hildenbrand (Arm)
2026-10-27 13:49 ` Gregory Price (Meta)
2026-10-27 14:25 ` David Hildenbrand (Arm)
2026-10-27 15:49 ` Gregory Price (Meta)
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=20261027042204.3741307-3-gourry@gourry.net \
--to=gourry@gourry.net \
--cc=akpm@linux-foundation.org \
--cc=anshuman.khandual@arm.com \
--cc=brendan.jackman@linux.dev \
--cc=david@kernel.org \
--cc=hannes@cmpxchg.org \
--cc=iamjoonsoo.kim@lge.com \
--cc=kernel-team@meta.com \
--cc=liam@infradead.org \
--cc=linmiaohe@huawei.com \
--cc=linux-cxl@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=mhocko@suse.com \
--cc=muchun.song@linux.dev \
--cc=nao.horiguchi@gmail.com \
--cc=osalvador@suse.de \
--cc=rppt@kernel.org \
--cc=stable@vger.kernel.org \
--cc=surenb@google.com \
--cc=vbabka@kernel.org \
--cc=ziy@nvidia.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®