[PATCH v6 04/10] crash_core: serialize crash header preparation against hotplug
From: Wandun Chen
Date: Wed Sep 02 2026 - 03:36:53 EST
From: Wandun Chen <chenwandun@xxxxxxxxxxx>
crash_prepare_headers() counts memory ranges before populating the
allocated crash_mem array. The weak implementation used by ARM64,
RISC-V and LoongArch walks memblock.memory, while x86 performs the same
two-pass operation over system RAM resources. Concurrent memory hotplug
can change range source between the two walks and make the populate
pass overflow cmem->ranges.
Take device_hotplug_lock when preparing crash headers during
kexec_file_load(). The x86 memory hotplug path already takes
device_hotplug_lock, so call __crash_prepare_headers() directly
to avoid recursive locking.
Sashiko reported this issue in [1].
Fixes: 3751e728cef2 ("arm64: kexec_file: add crash dump support")
Fixes: 1bcca8620a91 ("LoongArch: Add crash dump support for kexec_file")
Fixes: 8acea455fafa ("RISC-V: Support for kexec_file on panic")
Fixes: dd5f726076cc ("kexec: support for kexec on panic using new system call")
Signed-off-by: Wandun Chen <chenwandun@xxxxxxxxxxx>
Link: https://sashiko.dev/#/message/20260806101002.1F84E1F000E9@xxxxxxxxxxxxxxx [1]
---
arch/x86/kernel/crash.c | 2 +-
include/linux/crash_core.h | 2 ++
kernel/crash_core.c | 17 +++++++++++++++--
3 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index e681ec9cf1dc..284d78bc3fd0 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -465,7 +465,7 @@ void arch_crash_handle_hotplug_event(struct kimage *image, void *arg)
* Create the new elfcorehdr reflecting the changes to CPU and/or
* memory resources.
*/
- if (crash_prepare_headers(IS_ENABLED(CONFIG_X86_64), &elfbuf, &elfsz, NULL)) {
+ if (__crash_prepare_headers(IS_ENABLED(CONFIG_X86_64), &elfbuf, &elfsz, NULL)) {
pr_err("unable to create new elfcorehdr");
goto out;
}
diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h
index bc087124cd78..28e7a81cf263 100644
--- a/include/linux/crash_core.h
+++ b/include/linux/crash_core.h
@@ -61,6 +61,8 @@ extern int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_ma
void **addr, unsigned long *sz);
extern int crash_prepare_headers(int need_kernel_map, void **addr,
unsigned long *sz, unsigned long *nr_mem_ranges);
+int __crash_prepare_headers(int need_kernel_map, void **addr, unsigned long *sz,
+ unsigned long *nr_mem_ranges);
extern int crash_exclude_core_ranges(struct crash_mem **cmem);
struct kimage;
diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 77285ae3ce60..3adee1ae120c 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -16,6 +16,7 @@
#include <linux/mm.h>
#include <linux/cpuhotplug.h>
#include <linux/memblock.h>
+#include <linux/device.h>
#include <linux/kmemleak.h>
#include <linux/crash_core.h>
#include <linux/reboot.h>
@@ -338,8 +339,8 @@ int crash_exclude_core_ranges(struct crash_mem **cmem)
return 0;
}
-int crash_prepare_headers(int need_kernel_map, void **addr, unsigned long *sz,
- unsigned long *nr_mem_ranges)
+int __crash_prepare_headers(int need_kernel_map, void **addr, unsigned long *sz,
+ unsigned long *nr_mem_ranges)
{
unsigned int max_nr_ranges;
struct crash_mem *cmem;
@@ -376,6 +377,18 @@ int crash_prepare_headers(int need_kernel_map, void **addr, unsigned long *sz,
return ret;
}
+int crash_prepare_headers(int need_kernel_map, void **addr, unsigned long *sz,
+ unsigned long *nr_mem_ranges)
+{
+ int ret;
+
+ lock_device_hotplug();
+ ret = __crash_prepare_headers(need_kernel_map, addr, sz, nr_mem_ranges);
+ unlock_device_hotplug();
+
+ return ret;
+}
+
/**
* crash_exclude_mem_range - exclude a mem range for existing ranges
* @mem: mem->range contains an array of ranges sorted in ascending order
--
2.43.0