The arch_crash_handle_hotplug_event() interface currently lacks the CPU
index associated with hotplug events. This forces architecture handlers,
specifically on PowerPC, to unconditionally update the crash Flattened
Device Tree (FDT) for every CPU online event which should only be done
in case of DLPAR operations which add/remove new device tree node under the
/cpus. On large systems with crash kernel loaded, this behavior causes a
significant performance bottleneck. For example, during SMT switch
operations involving 1400 CPUs, the redundant execution of
update_crash_fdt() adds over half an hour of overhead

As shown in the ftrace function graph:
   83)   bash-14351   | $ 2283891 us  |     } /* update_cpus_node */

This patch passes the CPU index to the arch-specific handlers and
modifies the PowerPC implementation to check cpus_booted_once_mask. If
a CPU has been previously initialized, its FDT node is already present,
allowing the handler to skip the redundant update_crash_fdt() call.

Fixes: b741092d5976 ("powerpc/crash: add crash CPU hotplug support")
Signed-off-by: Vishal Chourasia <[email protected]>
---
 arch/powerpc/include/asm/kexec.h | 2 +-
 arch/powerpc/kexec/crash.c       | 5 +++--
 arch/x86/include/asm/kexec.h     | 2 +-
 arch/x86/kernel/crash.c          | 2 +-
 include/linux/crash_core.h       | 2 +-
 kernel/crash_core.c              | 2 +-
 6 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h
index bd4a6c42a5f3..2d6d32942bc0 100644
--- a/arch/powerpc/include/asm/kexec.h
+++ b/arch/powerpc/include/asm/kexec.h
@@ -137,7 +137,7 @@ static inline void crash_setup_regs(struct pt_regs *newregs,
 }
 
 #ifdef CONFIG_CRASH_HOTPLUG
-void arch_crash_handle_hotplug_event(struct kimage *image, void *arg);
+void arch_crash_handle_hotplug_event(struct kimage *image, int cpu, void *arg);
 #define arch_crash_handle_hotplug_event arch_crash_handle_hotplug_event
 
 int arch_crash_hotplug_support(struct kimage *image, unsigned long 
kexec_flags);
diff --git a/arch/powerpc/kexec/crash.c b/arch/powerpc/kexec/crash.c
index a325c1c02f96..d280883c8ab6 100644
--- a/arch/powerpc/kexec/crash.c
+++ b/arch/powerpc/kexec/crash.c
@@ -568,7 +568,7 @@ int arch_crash_hotplug_support(struct kimage *image, 
unsigned long kexec_flags)
  *            part of the FDT.
  * Memory add/remove: No action is taken as this is not yet supported.
  */
-void arch_crash_handle_hotplug_event(struct kimage *image, void *arg)
+void arch_crash_handle_hotplug_event(struct kimage *image, int cpu, void *arg)
 {
        struct memory_notify *mn;
 
@@ -577,7 +577,8 @@ void arch_crash_handle_hotplug_event(struct kimage *image, 
void *arg)
                return;
 
        case KEXEC_CRASH_HP_ADD_CPU:
-               update_crash_fdt(image);
+               if (!cpumask_test_cpu(cpu, &cpus_booted_once_mask))
+                       update_crash_fdt(image);
                break;
 
        case KEXEC_CRASH_HP_REMOVE_MEMORY:
diff --git a/arch/x86/include/asm/kexec.h b/arch/x86/include/asm/kexec.h
index 5cfb27f26583..57f5c5067267 100644
--- a/arch/x86/include/asm/kexec.h
+++ b/arch/x86/include/asm/kexec.h
@@ -222,7 +222,7 @@ int arch_kimage_file_post_load_cleanup(struct kimage 
*image);
 extern void kdump_nmi_shootdown_cpus(void);
 
 #ifdef CONFIG_CRASH_HOTPLUG
-void arch_crash_handle_hotplug_event(struct kimage *image, void *arg);
+void arch_crash_handle_hotplug_event(struct kimage *image, int cpu, void *arg);
 #define arch_crash_handle_hotplug_event arch_crash_handle_hotplug_event
 
 int arch_crash_hotplug_support(struct kimage *image, unsigned long 
kexec_flags);
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index 335fd2ee9766..dda4ad1a163e 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -508,7 +508,7 @@ unsigned int arch_crash_get_elfcorehdr_size(void)
  *
  * Prepare the new elfcorehdr and replace the existing elfcorehdr.
  */
-void arch_crash_handle_hotplug_event(struct kimage *image, void *arg)
+void arch_crash_handle_hotplug_event(struct kimage *image, int cpu, void *arg)
 {
        void *elfbuf = NULL, *old_elfcorehdr;
        unsigned long nr_mem_ranges;
diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h
index d35726d6a415..118e2e03e0b5 100644
--- a/include/linux/crash_core.h
+++ b/include/linux/crash_core.h
@@ -42,7 +42,7 @@ static inline int crash_load_dm_crypt_keys(struct kimage 
*image) {return 0; }
 #endif
 
 #ifndef arch_crash_handle_hotplug_event
-static inline void arch_crash_handle_hotplug_event(struct kimage *image, void 
*arg) { }
+static inline void arch_crash_handle_hotplug_event(struct kimage *image, int 
cpu, void *arg) { }
 #endif
 
 int crash_check_hotplug_support(void);
diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 3952b3e102e0..27c6f57e5169 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -634,7 +634,7 @@ static void crash_handle_hotplug_event(unsigned int 
hp_action, unsigned int cpu,
        image->hp_action = hp_action;
 
        /* Now invoke arch-specific update handler */
-       arch_crash_handle_hotplug_event(image, arg);
+       arch_crash_handle_hotplug_event(image, cpu, arg);
 
        /* No longer handling a hotplug event */
        image->hp_action = KEXEC_CRASH_HP_NONE;
-- 
2.53.0


Reply via email to