aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHidehiro Kawai <hidehiro.kawai.ez@hitachi.com>2016-10-11 16:54:23 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-11 18:06:32 -0400
commit0ee59413c967c35a6dd2dbdab605b4cd42025ee5 (patch)
treee3325918b5b8d40924eac2b3cc2f2a1f8467048a
parent2b6b535d9158b822a45080b3d6d5b2993fd49e5a (diff)
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>
-rw-r--r--arch/x86/include/asm/kexec.h1
-rw-r--r--arch/x86/include/asm/smp.h1
-rw-r--r--arch/x86/kernel/crash.c22
-rw-r--r--arch/x86/kernel/smp.c5
-rw-r--r--kernel/panic.c47
5 files changed, 66 insertions, 10 deletions
diff --git a/arch/x86/include/asm/kexec.h b/arch/x86/include/asm/kexec.h
index d2434c1cad05..282630e4c6ea 100644
--- a/arch/x86/include/asm/kexec.h
+++ b/arch/x86/include/asm/kexec.h
@@ -210,6 +210,7 @@ struct kexec_entry64_regs {
210 210
211typedef void crash_vmclear_fn(void); 211typedef void crash_vmclear_fn(void);
212extern crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss; 212extern crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss;
213extern void kdump_nmi_shootdown_cpus(void);
213 214
214#endif /* __ASSEMBLY__ */ 215#endif /* __ASSEMBLY__ */
215 216
diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h
index 19980b36f394..026ea82ecc60 100644
--- a/arch/x86/include/asm/smp.h
+++ b/arch/x86/include/asm/smp.h
@@ -47,6 +47,7 @@ struct smp_ops {
47 void (*smp_cpus_done)(unsigned max_cpus); 47 void (*smp_cpus_done)(unsigned max_cpus);
48 48
49 void (*stop_other_cpus)(int wait); 49 void (*stop_other_cpus)(int wait);
50 void (*crash_stop_other_cpus)(void);
50 void (*smp_send_reschedule)(int cpu); 51 void (*smp_send_reschedule)(int cpu);
51 52
52 int (*cpu_up)(unsigned cpu, struct task_struct *tidle); 53 int (*cpu_up)(unsigned cpu, struct task_struct *tidle);
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index 9616cf76940c..650830e39e3a 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -133,15 +133,31 @@ static void kdump_nmi_callback(int cpu, struct pt_regs *regs)
133 disable_local_APIC(); 133 disable_local_APIC();
134} 134}
135 135
136static void kdump_nmi_shootdown_cpus(void) 136void kdump_nmi_shootdown_cpus(void)
137{ 137{
138 nmi_shootdown_cpus(kdump_nmi_callback); 138 nmi_shootdown_cpus(kdump_nmi_callback);
139 139
140 disable_local_APIC(); 140 disable_local_APIC();
141} 141}
142 142
143/* Override the weak function in kernel/panic.c */
144void 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#else 159#else
144static void kdump_nmi_shootdown_cpus(void) 160void crash_smp_send_stop(void)
145{ 161{
146 /* There are no cpus to shootdown */ 162 /* There are no cpus to shootdown */
147} 163}
@@ -160,7 +176,7 @@ void native_machine_crash_shutdown(struct pt_regs *regs)
160 /* The kernel is broken so disable interrupts */ 176 /* The kernel is broken so disable interrupts */
161 local_irq_disable(); 177 local_irq_disable();
162 178
163 kdump_nmi_shootdown_cpus(); 179 crash_smp_send_stop();
164 180
165 /* 181 /*
166 * VMCLEAR VMCSs loaded on this cpu if needed. 182 * VMCLEAR VMCSs loaded on this cpu if needed.
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index 658777cf3851..68f8cc222f25 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -32,6 +32,8 @@
32#include <asm/nmi.h> 32#include <asm/nmi.h>
33#include <asm/mce.h> 33#include <asm/mce.h>
34#include <asm/trace/irq_vectors.h> 34#include <asm/trace/irq_vectors.h>
35#include <asm/kexec.h>
36
35/* 37/*
36 * Some notes on x86 processor bugs affecting SMP operation: 38 * Some notes on x86 processor bugs affecting SMP operation:
37 * 39 *
@@ -342,6 +344,9 @@ struct smp_ops smp_ops = {
342 .smp_cpus_done = native_smp_cpus_done, 344 .smp_cpus_done = native_smp_cpus_done,
343 345
344 .stop_other_cpus = native_stop_other_cpus, 346 .stop_other_cpus = native_stop_other_cpus,
347#if defined(CONFIG_KEXEC_CORE)
348 .crash_stop_other_cpus = kdump_nmi_shootdown_cpus,
349#endif
345 .smp_send_reschedule = native_smp_send_reschedule, 350 .smp_send_reschedule = native_smp_send_reschedule,
346 351
347 .cpu_up = native_cpu_up, 352 .cpu_up = native_cpu_up,
diff --git a/kernel/panic.c b/kernel/panic.c
index ca8cea1ef673..e6480e20379e 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -71,6 +71,32 @@ void __weak nmi_panic_self_stop(struct pt_regs *regs)
71 panic_smp_self_stop(); 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 */
80void __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
74atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID); 100atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID);
75 101
76/* 102/*
@@ -164,14 +190,21 @@ void panic(const char *fmt, ...)
164 if (!_crash_kexec_post_notifiers) { 190 if (!_crash_kexec_post_notifiers) {
165 printk_nmi_flush_on_panic(); 191 printk_nmi_flush_on_panic();
166 __crash_kexec(NULL); 192 __crash_kexec(NULL);
167 }
168 193
169 /* 194 /*
170 * Note smp_send_stop is the usual smp shutdown function, which 195 * Note smp_send_stop is the usual smp shutdown function, which
171 * unfortunately means it may not be hardened to work in a panic 196 * unfortunately means it may not be hardened to work in a
172 * situation. 197 * panic situation.
173 */ 198 */
174 smp_send_stop(); 199 smp_send_stop();
200 } else {
201 /*
202 * If we want to do crash dump after notifier calls and
203 * kmsg_dump, we will need architecture dependent extra
204 * works in addition to stopping other CPUs.
205 */
206 crash_smp_send_stop();
207 }
175 208
176 /* 209 /*
177 * Run any panic handlers, including those that might need to 210 * Run any panic handlers, including those that might need to