[PATCH v2 3/3] drivers/base/memory: fix locking for poison accounting lookup

Muchun Song
2026-04-28T08:52:47Z

memblk_nr_poison_inc() and memblk_nr_poison_sub() call
find_memory_block_by_id(), which requires device_hotplug_lock to
serialize the xarray lookup against memory block removal.

Take device_hotplug_lock around the lookup and nr_hwpoison update so
the memory block cannot disappear between xa_load() and get_device().

Fixes: 5033091de814 ("mm/hwpoison: introduce per-memory_block hwpoison counter")
Cc: stable@vger.kernel.org
Signed-off-by: Muchun Song <songmuchun@bytedance.com>
---
drivers/base/memory.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 6981b55d582a..f76aee29e9a5 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -1228,23 +1228,29 @@ int walk_dynamic_memory_groups(int nid, walk_memory_groups_func_t func,
void memblk_nr_poison_inc(unsigned long pfn)
{
const unsigned long block_id = pfn_to_block_id(pfn);
- struct memory_block *mem = find_memory_block_by_id(block_id);
+ struct memory_block *mem;

+ lock_device_hotplug();
+ mem = find_memory_block_by_id(block_id);
if (mem) {
atomic_long_inc(&mem->nr_hwpoison);
put_device(&mem->dev);
}
+ unlock_device_hotplug();
}

void memblk_nr_poison_sub(unsigned long pfn, long i)
{
const unsigned long block_id = pfn_to_block_id(pfn);
- struct memory_block *mem = find_memory_block_by_id(block_id);
+ struct memory_block *mem;

+ lock_device_hotplug();
+ mem = find_memory_block_by_id(block_id);
if (mem) {
atomic_long_sub(i, &mem->nr_hwpoison);
put_device(&mem->dev);
}
+ unlock_device_hotplug();
}

static unsigned long memblk_nr_poison(struct memory_block *mem)
--
2.20.1