]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
x86/panic: replace smp_send_stop() with kdump friendly version in panic path
authorHidehiro Kawai <hidehiro.kawai.ez@hitachi.com>
Tue, 11 Oct 2016 20:54:23 +0000 (13:54 -0700)
committerBen Hutchings <ben@decadent.org.uk>
Thu, 23 Feb 2017 03:54:11 +0000 (03:54 +0000)
commit 0ee59413c967c35a6dd2dbdab605b4cd42025ee5 upstream.

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>
[bwh: Backported to 3.16: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
arch/x86/include/asm/kexec.h
arch/x86/include/asm/smp.h
arch/x86/kernel/crash.c
arch/x86/kernel/smp.c
kernel/panic.c

index 17483a492f1882f218849bedd1c26d8a970d433f..0c59df3664d5969458c9b714b3401d1f2b8ecf1d 100644 (file)
@@ -165,6 +165,7 @@ struct kimage_arch {
 
 typedef void crash_vmclear_fn(void);
 extern crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss;
+extern void kdump_nmi_shootdown_cpus(void);
 
 #endif /* __ASSEMBLY__ */
 
index 8cd27e08e23c47cec2f736b6b674b921554eb680..63baf16934d0ce0aa8185bcc39772c6bdf1d420b 100644 (file)
@@ -69,6 +69,7 @@ struct smp_ops {
        void (*smp_cpus_done)(unsigned max_cpus);
 
        void (*stop_other_cpus)(int wait);
+       void (*crash_stop_other_cpus)(void);
        void (*smp_send_reschedule)(int cpu);
 
        int (*cpu_up)(unsigned cpu, struct task_struct *tidle);
index 507de80665942b87a148e032fd8aeedfeb76c70b..19f10dac8fe6c2a31d7ad618f3e793680d0dabc7 100644 (file)
@@ -82,7 +82,7 @@ static void kdump_nmi_callback(int cpu, struct pt_regs *regs)
        disable_local_APIC();
 }
 
-static void kdump_nmi_shootdown_cpus(void)
+void kdump_nmi_shootdown_cpus(void)
 {
        in_crash_kexec = 1;
        nmi_shootdown_cpus(kdump_nmi_callback);
@@ -90,8 +90,24 @@ static void kdump_nmi_shootdown_cpus(void)
        disable_local_APIC();
 }
 
+/* Override the weak function in kernel/panic.c */
+void crash_smp_send_stop(void)
+{
+       static int cpus_stopped;
+
+       if (cpus_stopped)
+               return;
+
+       if (smp_ops.crash_stop_other_cpus)
+               smp_ops.crash_stop_other_cpus();
+       else
+               smp_send_stop();
+
+       cpus_stopped = 1;
+}
+
 #else
-static void kdump_nmi_shootdown_cpus(void)
+void crash_smp_send_stop(void)
 {
        /* There are no cpus to shootdown */
 }
@@ -110,7 +126,7 @@ void native_machine_crash_shutdown(struct pt_regs *regs)
        /* The kernel is broken so disable interrupts */
        local_irq_disable();
 
-       kdump_nmi_shootdown_cpus();
+       crash_smp_send_stop();
 
        /*
         * VMCLEAR VMCSs loaded on this cpu if needed.
index be8e1bde07aa47ff373f0245e0f4b7d6d2edcfd5..00e67d05cbd0da2fddc8a23f97f57dc981997db1 100644 (file)
@@ -31,6 +31,8 @@
 #include <asm/apic.h>
 #include <asm/nmi.h>
 #include <asm/trace/irq_vectors.h>
+#include <asm/kexec.h>
+
 /*
  *     Some notes on x86 processor bugs affecting SMP operation:
  *
@@ -347,6 +349,9 @@ struct smp_ops smp_ops = {
        .smp_cpus_done          = native_smp_cpus_done,
 
        .stop_other_cpus        = native_stop_other_cpus,
+#if defined(CONFIG_KEXEC_CORE)
+       .crash_stop_other_cpus  = kdump_nmi_shootdown_cpus,
+#endif
        .smp_send_reschedule    = native_smp_send_reschedule,
 
        .cpu_up                 = native_cpu_up,
index 51266521e17374ab6f836d07138f54e02544b0a1..4de988c2aaec3253f9fbfc40be5c5dcf3ff4d568 100644 (file)
@@ -60,6 +60,32 @@ void __weak panic_smp_self_stop(void)
                cpu_relax();
 }
 
+/*
+ * Stop other CPUs in panic.  Architecture dependent code may override this
+ * with more suitable version.  For example, if the architecture supports
+ * crash dump, it should save registers of each stopped CPU and disable
+ * per-CPU features such as virtualization extensions.
+ */
+void __weak crash_smp_send_stop(void)
+{
+       static int cpus_stopped;
+
+       /*
+        * This function can be called twice in panic path, but obviously
+        * we execute this only once.
+        */
+       if (cpus_stopped)
+               return;
+
+       /*
+        * Note smp_send_stop is the usual smp shutdown function, which
+        * unfortunately means it may not be hardened to work in a panic
+        * situation.
+        */
+       smp_send_stop();
+       cpus_stopped = 1;
+}
+
 /**
  *     panic - halt the system
  *     @fmt: The text string to print
@@ -117,15 +143,23 @@ void panic(const char *fmt, ...)
         * If we want to run this after calling panic_notifiers, pass
         * the "crash_kexec_post_notifiers" option to the kernel.
         */
-       if (!crash_kexec_post_notifiers)
+       if (!crash_kexec_post_notifiers) {
                crash_kexec(NULL);
 
-       /*
-        * Note smp_send_stop is the usual smp shutdown function, which
-        * unfortunately means it may not be hardened to work in a panic
-        * situation.
-        */
-       smp_send_stop();
+               /*
+                * Note smp_send_stop is the usual smp shutdown function, which
+                * unfortunately means it may not be hardened to work in a
+                * panic situation.
+                */
+               smp_send_stop();
+       } else {
+               /*
+                * If we want to do crash dump after notifier calls and
+                * kmsg_dump, we will need architecture dependent extra
+                * works in addition to stopping other CPUs.
+                */
+               crash_smp_send_stop();
+       }
 
        /*
         * Run any panic handlers, including those that might need to