Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/panic: replace smp_send_stop() with kdump friendly version in panic path

Daniel Walker reported problems which happens when
crash_kexec_post_notifiers kernel option is enabled
(https://lkml.org/lkml/2015/6/24/44).

In that case, smp_send_stop() is called before entering kdump routines
which assume other CPUs are still online. As the result, for x86, kdump
routines fail to save other CPUs' registers and disable virtualization
extensions.

To fix this problem, call a new kdump friendly function,
crash_smp_send_stop(), instead of the smp_send_stop() when
crash_kexec_post_notifiers is enabled. crash_smp_send_stop() is a weak
function, and it just call smp_send_stop(). Architecture codes should
override it so that kdump can work appropriately. This patch only
provides x86-specific version.

For Xen's PV kernel, just keep the current behavior.

NOTES:

- Right solution would be to place crash_smp_send_stop() before
__crash_kexec() invocation in all cases and remove smp_send_stop(), but
we can't do that until all architectures implement own
crash_smp_send_stop()

- crash_smp_send_stop()-like work is still needed by
machine_crash_shutdown() because crash_kexec() can be called without
entering panic()

Fixes: f06e5153f4ae (kernel/panic.c: add "crash_kexec_post_notifiers" option)
Link: http://lkml.kernel.org/r/20160810080948.11028.15344.stgit@sysi4-13.yrl.intra.hitachi.co.jp
Signed-off-by: Hidehiro Kawai <hidehiro.kawai.ez@hitachi.com>
Reported-by: Daniel Walker <dwalker@fifo99.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Daniel Walker <dwalker@fifo99.com>
Cc: Xunlei Pang <xpang@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: David Vrabel <david.vrabel@citrix.com>
Cc: Toshi Kani <toshi.kani@hpe.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: David Daney <david.daney@cavium.com>
Cc: Aaro Koskinen <aaro.koskinen@iki.fi>
Cc: "Steven J. Hill" <steven.hill@cavium.com>
Cc: Corey Minyard <cminyard@mvista.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Hidehiro Kawai and committed by
Linus Torvalds
0ee59413 2b6b535d

+66 -10
+1
arch/x86/include/asm/kexec.h
··· 210 210 211 211 typedef void crash_vmclear_fn(void); 212 212 extern crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss; 213 + extern void kdump_nmi_shootdown_cpus(void); 213 214 214 215 #endif /* __ASSEMBLY__ */ 215 216
+1
arch/x86/include/asm/smp.h
··· 47 47 void (*smp_cpus_done)(unsigned max_cpus); 48 48 49 49 void (*stop_other_cpus)(int wait); 50 + void (*crash_stop_other_cpus)(void); 50 51 void (*smp_send_reschedule)(int cpu); 51 52 52 53 int (*cpu_up)(unsigned cpu, struct task_struct *tidle);
+19 -3
arch/x86/kernel/crash.c
··· 133 133 disable_local_APIC(); 134 134 } 135 135 136 - static void kdump_nmi_shootdown_cpus(void) 136 + void kdump_nmi_shootdown_cpus(void) 137 137 { 138 138 nmi_shootdown_cpus(kdump_nmi_callback); 139 139 140 140 disable_local_APIC(); 141 141 } 142 142 143 + /* Override the weak function in kernel/panic.c */ 144 + void crash_smp_send_stop(void) 145 + { 146 + static int cpus_stopped; 147 + 148 + if (cpus_stopped) 149 + return; 150 + 151 + if (smp_ops.crash_stop_other_cpus) 152 + smp_ops.crash_stop_other_cpus(); 153 + else 154 + smp_send_stop(); 155 + 156 + cpus_stopped = 1; 157 + } 158 + 143 159 #else 144 - static void kdump_nmi_shootdown_cpus(void) 160 + void crash_smp_send_stop(void) 145 161 { 146 162 /* There are no cpus to shootdown */ 147 163 } ··· 176 160 /* The kernel is broken so disable interrupts */ 177 161 local_irq_disable(); 178 162 179 - kdump_nmi_shootdown_cpus(); 163 + crash_smp_send_stop(); 180 164 181 165 /* 182 166 * VMCLEAR VMCSs loaded on this cpu if needed.
+5
arch/x86/kernel/smp.c
··· 32 32 #include <asm/nmi.h> 33 33 #include <asm/mce.h> 34 34 #include <asm/trace/irq_vectors.h> 35 + #include <asm/kexec.h> 36 + 35 37 /* 36 38 * Some notes on x86 processor bugs affecting SMP operation: 37 39 * ··· 344 342 .smp_cpus_done = native_smp_cpus_done, 345 343 346 344 .stop_other_cpus = native_stop_other_cpus, 345 + #if defined(CONFIG_KEXEC_CORE) 346 + .crash_stop_other_cpus = kdump_nmi_shootdown_cpus, 347 + #endif 347 348 .smp_send_reschedule = native_smp_send_reschedule, 348 349 349 350 .cpu_up = native_cpu_up,
+40 -7
kernel/panic.c
··· 71 71 panic_smp_self_stop(); 72 72 } 73 73 74 + /* 75 + * Stop other CPUs in panic. Architecture dependent code may override this 76 + * with more suitable version. For example, if the architecture supports 77 + * crash dump, it should save registers of each stopped CPU and disable 78 + * per-CPU features such as virtualization extensions. 79 + */ 80 + void __weak crash_smp_send_stop(void) 81 + { 82 + static int cpus_stopped; 83 + 84 + /* 85 + * This function can be called twice in panic path, but obviously 86 + * we execute this only once. 87 + */ 88 + if (cpus_stopped) 89 + return; 90 + 91 + /* 92 + * Note smp_send_stop is the usual smp shutdown function, which 93 + * unfortunately means it may not be hardened to work in a panic 94 + * situation. 95 + */ 96 + smp_send_stop(); 97 + cpus_stopped = 1; 98 + } 99 + 74 100 atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID); 75 101 76 102 /* ··· 190 164 if (!_crash_kexec_post_notifiers) { 191 165 printk_nmi_flush_on_panic(); 192 166 __crash_kexec(NULL); 193 - } 194 167 195 - /* 196 - * Note smp_send_stop is the usual smp shutdown function, which 197 - * unfortunately means it may not be hardened to work in a panic 198 - * situation. 199 - */ 200 - smp_send_stop(); 168 + /* 169 + * Note smp_send_stop is the usual smp shutdown function, which 170 + * unfortunately means it may not be hardened to work in a 171 + * panic situation. 172 + */ 173 + smp_send_stop(); 174 + } else { 175 + /* 176 + * If we want to do crash dump after notifier calls and 177 + * kmsg_dump, we will need architecture dependent extra 178 + * works in addition to stopping other CPUs. 179 + */ 180 + crash_smp_send_stop(); 181 + } 201 182 202 183 /* 203 184 * Run any panic handlers, including those that might need to