[PATCH v6 12/14] crash: Normalize the kexec_load elfcorehdr at load time
From: Jinjie Ruan
Date: Mon Sep 21 2026 - 05:11:42 EST
For kexec_load() the kernel does not build the elfcorehdr, so it is only
rewritten by the first crash hotplug event. CPU hotplug events do not
change the elfcorehdr, but they may run without device_hotplug_lock
(e.g. CPU offlining during suspend), so they cannot perform that rewrite
without racing with memory hotplug.
Normalize the elfcorehdr once when the crash image is installed via
crash_hotplug_prepare_elfcorehdr(), while device_hotplug_lock can still
be taken safely, and let the hotplug paths skip CPU events entirely.
Architectures that do not need the rewrite (e.g. powerpc) treat
KEXEC_CRASH_HP_NONE as a no-op.
The x86 crash hotplug handler now skips CPU hotplug events
unconditionally, so nothing reads image->elfcorehdr_updated anymore.
Drop the field and the code that maintains it.
Slightly tested on x86_64 with kexec_load (--kexec-syscall --hotplug),
it boots successfully into the second kernel.
Cc: Madhavan Srinivasan <maddy@xxxxxxxxxxxxx>
Cc: Michael Ellerman <mpe@xxxxxxxxxxxxxx>
Cc: Nicholas Piggin <npiggin@xxxxxxxxx>
Cc: "Christophe Leroy (CS GROUP)" <chleroy@xxxxxxxxxx>
Cc: "Ritesh Harjani (IBM)" <ritesh.list@xxxxxxxxx>
Cc: Shrikanth Hegde <sshegde@xxxxxxxxxxxxx>
Cc: Thomas Gleixner <tglx@xxxxxxxxxx>
Cc: Ingo Molnar <mingo@xxxxxxxxxx>
Cc: Borislav Petkov <bp@xxxxxxxxx>
Cc: Dave Hansen <dave.hansen@xxxxxxxxxxxxxxx>
Cc: "H. Peter Anvin" <hpa@xxxxxxxxx>
Cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
Cc: Baoquan He <baoquan.he@xxxxxxxxx>
Cc: Mike Rapoport <rppt@xxxxxxxxxx>
Cc: Pasha Tatashin <pasha.tatashin@xxxxxxxxxx>
Cc: Pratyush Yadav <pratyush@xxxxxxxxxx>
Cc: Dave Young <ruirui.yang@xxxxxxxxx>
Cc: Sourabh Jain <sourabhjain@xxxxxxxxxxxxx>
Signed-off-by: Jinjie Ruan <ruanjinjie@xxxxxxxxxx>
---
arch/powerpc/kexec/crash.c | 1 +
arch/x86/kernel/crash.c | 5 ++---
include/linux/crash_core.h | 1 +
include/linux/kexec.h | 1 -
kernel/crash_core.c | 20 +++++++++++++++++++-
kernel/kexec.c | 4 ++++
kernel/kexec_core.c | 1 -
7 files changed, 27 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/kexec/crash.c b/arch/powerpc/kexec/crash.c
index 775895f31037..8ede33740fc0 100644
--- a/arch/powerpc/kexec/crash.c
+++ b/arch/powerpc/kexec/crash.c
@@ -638,6 +638,7 @@ void arch_crash_handle_hotplug_event(struct kimage *image, void *arg)
struct memory_notify *mn;
switch (image->hp_action) {
+ case KEXEC_CRASH_HP_NONE:
case KEXEC_CRASH_HP_REMOVE_CPU:
return;
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index 3c9f4fbbe7ff..f34fa8dba028 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -457,9 +457,8 @@ void arch_crash_handle_hotplug_event(struct kimage *image, void *arg)
* possible CPUs, there is no need to update the elfcorehdr
* for additional CPU changes.
*/
- if ((image->file_mode || image->elfcorehdr_updated) &&
- ((image->hp_action == KEXEC_CRASH_HP_ADD_CPU) ||
- (image->hp_action == KEXEC_CRASH_HP_REMOVE_CPU)))
+ if (image->hp_action == KEXEC_CRASH_HP_ADD_CPU ||
+ image->hp_action == KEXEC_CRASH_HP_REMOVE_CPU)
return;
/*
diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h
index b1c816e98143..a740757dff35 100644
--- a/include/linux/crash_core.h
+++ b/include/linux/crash_core.h
@@ -39,6 +39,7 @@ static inline void arch_crash_handle_hotplug_event(struct kimage *image, void *a
#endif
int crash_check_hotplug_support(void);
+void crash_hotplug_prepare_elfcorehdr(struct kimage *image);
#ifndef arch_crash_hotplug_support
static inline int arch_crash_hotplug_support(struct kimage *image, unsigned long kexec_flags)
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 72258d813301..f1f218e46db0 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -404,7 +404,6 @@ struct kimage {
#ifdef CONFIG_CRASH_HOTPLUG
int hp_action;
int elfcorehdr_index;
- bool elfcorehdr_updated;
#endif
#ifdef CONFIG_IMA_KEXEC
diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 4a990b17b66c..b638ad0e5ba2 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -742,7 +742,6 @@ static void crash_handle_hotplug_event(unsigned int hp_action, unsigned int cpu,
/* No longer handling a hotplug event */
image->hp_action = KEXEC_CRASH_HP_NONE;
- image->elfcorehdr_updated = true;
/* Change back to read-only */
arch_kexec_protect_crashkres();
@@ -754,6 +753,25 @@ static void crash_handle_hotplug_event(unsigned int hp_action, unsigned int cpu,
crash_hotplug_unlock();
}
+void crash_hotplug_prepare_elfcorehdr(struct kimage *image)
+{
+ if (!image || !image->hotplug_support || image->file_mode)
+ return;
+
+ crash_find_elfcorehdr(image);
+ if (image->elfcorehdr_index < 0)
+ return;
+
+ /*
+ * kexec_load() images are not normalized at load, so do it here while
+ * the lock is still free to take. hp_action is KEXEC_CRASH_HP_NONE,
+ * which the arch handler treats as "just rebuild the elfcorehdr".
+ */
+ lock_device_hotplug();
+ arch_crash_handle_hotplug_event(image, NULL);
+ unlock_device_hotplug();
+}
+
static int crash_memhp_notifier(struct notifier_block *nb, unsigned long val, void *arg)
{
switch (val) {
diff --git a/kernel/kexec.c b/kernel/kexec.c
index 90756dc6339b..ea9ba00bc786 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -166,6 +166,10 @@ static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
/* Install the new kernel and uninstall the old */
image = xchg(dest_image, image);
+#ifdef CONFIG_CRASH_HOTPLUG
+ if ((flags & KEXEC_ON_CRASH) && kexec_crash_image)
+ crash_hotplug_prepare_elfcorehdr(kexec_crash_image);
+#endif
out:
#ifdef CONFIG_CRASH_DUMP
if ((flags & KEXEC_ON_CRASH) && kexec_crash_image)
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 31c8228318a7..c36a5e8b400e 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -251,7 +251,6 @@ struct kimage *do_kimage_alloc_init(void)
#ifdef CONFIG_CRASH_HOTPLUG
image->hp_action = KEXEC_CRASH_HP_NONE;
image->elfcorehdr_index = -1;
- image->elfcorehdr_updated = false;
#endif
return image;
--
2.34.1