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 6/6] mm/hwpoison-inject: keep the page online while filtering it
Date: Tue, 27 Oct 2026 00:22:04 -0400 [thread overview]
Message-ID: <20261027042204.3741307-7-gourry@gourry.net> (raw)
In-Reply-To: <20261027042204.3741307-1-gourry@gourry.net>
Injecting a memory error with the filter enabled while the memory is
hot-removed can crash. hwpoison_inject() checks the pfn with
pfn_valid(), then runs shake_folio() and the filter on its page, which
can sleep in lru_add_drain_all():
CPU 1 (hwpoison_inject) CPU 2 (ACPI eject)
pfn_valid()
folio = page_folio(pfn_to_page())
offline_pages()
arch_remove_memory()
vmemmap freed
shake_folio(folio)
reads folio->flags
BUG: unable to handle page fault for address: ffd4000006040033
#PF: error_code(0x0000) - not-present page
RIP: 0010:shake_folio+0x2a/0x50
hwpoison_inject+0x232/0x4b0 [hwpoison_inject]
simple_attr_write_xsigned.constprop.0.isra.0+0x179/0x220
debugfs_attr_write+0x63/0x90
Until the filter stopped pinning the page, that reference held off
offline.
Hold get_online_mems() around the filter, check the pfn with
pfn_to_online_page() under it, and drop the hold before
memory_failure(), which takes it again. Offline and ZONE_DEVICE pages
never passed the filter anyway. Export get/put_online_mems() to the
module.
With the injector held at shake_folio() on a free DIMM page across an
eject, base faults in 3 of 3 runs. With this patch the eject waits, and
the injection then fails with -ENXIO, in 3 of 3.
Fixes: fd476720c9ba ("mm,hwpoison-inject: don't pin for hwpoison_filter")
Cc: stable@vger.kernel.org
Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
---
mm/hwpoison-inject.c | 55 +++++++++++++++++++++++++++++---------------
mm/memory_hotplug.c | 2 ++
2 files changed, 39 insertions(+), 18 deletions(-)
diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c
index a11222572f978..f6cc967b3a468 100644
--- a/mm/hwpoison-inject.c
+++ b/mm/hwpoison-inject.c
@@ -9,6 +9,7 @@
#include <linux/hugetlb.h>
#include <linux/page-flags.h>
#include <linux/memcontrol.h>
+#include <linux/memory_hotplug.h>
#include "internal.h"
static u32 hwpoison_filter_enable;
@@ -99,43 +100,61 @@ static int hwpoison_filter(struct page *p)
static struct dentry *hwpoison_dir;
-static int hwpoison_inject(void *data, u64 val)
+/* Returns true if the filter rejects the page at @pfn */
+static bool hwpoison_inject_filtered(unsigned long pfn)
{
- unsigned long pfn = val;
struct page *p;
struct folio *folio;
- int err;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- if (!pfn_valid(pfn))
- return -ENXIO;
- p = pfn_to_page(pfn);
+ /*
+ * Offline and ZONE_DEVICE pages are not LRU, hugetlb or free buddy
+ * pages, so the checks below never let them through.
+ */
+ p = pfn_to_online_page(pfn);
+ if (!p)
+ return true;
folio = page_folio(p);
- if (!hwpoison_filter_enable)
- goto inject;
-
shake_folio(folio);
/*
* This implies unable to support non-LRU pages except free page.
*/
if (!folio_test_lru(folio) && !folio_test_hugetlb(folio) &&
!is_free_buddy_page(p))
- return 0;
+ return true;
/*
* do a racy check to make sure PG_hwpoison will only be set for
* the targeted owner (or on a free page).
* memory_failure() will redo the check reliably inside page lock.
*/
- err = hwpoison_filter(&folio->page);
- if (err)
- return 0;
+ return hwpoison_filter(&folio->page);
+}
+
+static int hwpoison_inject(void *data, u64 val)
+{
+ unsigned long pfn = val;
+ bool filtered;
+ int err;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (!pfn_valid(pfn))
+ return -ENXIO;
+
+ if (hwpoison_filter_enable) {
+ /*
+ * Keep the page online while the filter looks at it.
+ * memory_failure() takes this again, so drop it first.
+ */
+ get_online_mems();
+ filtered = hwpoison_inject_filtered(pfn);
+ put_online_mems();
+ if (filtered)
+ return 0;
+ }
-inject:
pr_info("Injecting memory failure at pfn %#lx\n", pfn);
err = memory_failure(pfn, MF_SW_SIMULATED);
return (err == -EOPNOTSUPP) ? 0 : err;
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index b5d9e367b893d..fe2ed0894d49d 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -215,11 +215,13 @@ void get_online_mems(void)
{
percpu_down_read(&mem_hotplug_lock);
}
+EXPORT_SYMBOL_FOR_MODULES(get_online_mems, "hwpoison-inject");
void put_online_mems(void)
{
percpu_up_read(&mem_hotplug_lock);
}
+EXPORT_SYMBOL_FOR_MODULES(put_online_mems, "hwpoison-inject");
bool movable_node_enabled = false;
--
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 ` [PATCH 2/6] mm/page_owner: hold off memory offline while a page is read Gregory Price (Meta)
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 ` Gregory Price (Meta) [this message]
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-7-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®