Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/scottwood/linux...
[sfrench/cifs-2.6.git] / arch / powerpc / kernel / traps.c
index 410352acfa38318403c9080514942cc1e86ee85d..13c9dcdcba6922e32d4c00267201f47e9498f805 100644 (file)
@@ -114,6 +114,28 @@ static void pmac_backlight_unblank(void)
 static inline void pmac_backlight_unblank(void) { }
 #endif
 
+/*
+ * If oops/die is expected to crash the machine, return true here.
+ *
+ * This should not be expected to be 100% accurate, there may be
+ * notifiers registered or other unexpected conditions that may bring
+ * down the kernel. Or if the current process in the kernel is holding
+ * locks or has other critical state, the kernel may become effectively
+ * unusable anyway.
+ */
+bool die_will_crash(void)
+{
+       if (should_fadump_crash())
+               return true;
+       if (kexec_should_crash(current))
+               return true;
+       if (in_interrupt() || panic_on_oops ||
+                       !current->pid || is_global_init(current))
+               return true;
+
+       return false;
+}
+
 static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED;
 static int die_owner = -1;
 static unsigned int die_nest_count;
@@ -162,21 +184,9 @@ static void oops_end(unsigned long flags, struct pt_regs *regs,
 
        crash_fadump(regs, "die oops");
 
-       /*
-        * A system reset (0x100) is a request to dump, so we always send
-        * it through the crashdump code.
-        */
-       if (kexec_should_crash(current) || (TRAP(regs) == 0x100)) {
+       if (kexec_should_crash(current))
                crash_kexec(regs);
 
-               /*
-                * We aren't the primary crash CPU. We need to send it
-                * to a holding pattern to avoid it ending up in the panic
-                * code.
-                */
-               crash_kexec_secondary(regs);
-       }
-
        if (!signr)
                return;
 
@@ -202,18 +212,25 @@ NOKPROBE_SYMBOL(oops_end);
 static int __die(const char *str, struct pt_regs *regs, long err)
 {
        printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
-#ifdef CONFIG_PREEMPT
-       printk("PREEMPT ");
-#endif
-#ifdef CONFIG_SMP
-       printk("SMP NR_CPUS=%d ", NR_CPUS);
-#endif
+
+       if (IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN))
+               printk("LE ");
+       else
+               printk("BE ");
+
+       if (IS_ENABLED(CONFIG_PREEMPT))
+               pr_cont("PREEMPT ");
+
+       if (IS_ENABLED(CONFIG_SMP))
+               pr_cont("SMP NR_CPUS=%d ", NR_CPUS);
+
        if (debug_pagealloc_enabled())
-               printk("DEBUG_PAGEALLOC ");
-#ifdef CONFIG_NUMA
-       printk("NUMA ");
-#endif
-       printk("%s\n", ppc_md.name ? ppc_md.name : "");
+               pr_cont("DEBUG_PAGEALLOC ");
+
+       if (IS_ENABLED(CONFIG_NUMA))
+               pr_cont("NUMA ");
+
+       pr_cont("%s\n", ppc_md.name ? ppc_md.name : "");
 
        if (notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV) == NOTIFY_STOP)
                return 1;
@@ -296,17 +313,44 @@ void system_reset_exception(struct pt_regs *regs)
                        goto out;
        }
 
-       die("System Reset", regs, SIGABRT);
+       if (debugger(regs))
+               goto out;
+
+       /*
+        * A system reset is a request to dump, so we always send
+        * it through the crashdump code (if fadump or kdump are
+        * registered).
+        */
+       crash_fadump(regs, "System Reset");
+
+       crash_kexec(regs);
+
+       /*
+        * We aren't the primary crash CPU. We need to send it
+        * to a holding pattern to avoid it ending up in the panic
+        * code.
+        */
+       crash_kexec_secondary(regs);
+
+       /*
+        * No debugger or crash dump registered, print logs then
+        * panic.
+        */
+       __die("System Reset", regs, SIGABRT);
+
+       mdelay(2*MSEC_PER_SEC); /* Wait a little while for others to print */
+       add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
+       nmi_panic(regs, "System Reset");
 
 out:
 #ifdef CONFIG_PPC_BOOK3S_64
        BUG_ON(get_paca()->in_nmi == 0);
        if (get_paca()->in_nmi > 1)
-               panic("Unrecoverable nested System Reset");
+               nmi_panic(regs, "Unrecoverable nested System Reset");
 #endif
        /* Must die if the interrupt is not recoverable */
        if (!(regs->msr & MSR_RI))
-               panic("Unrecoverable System Reset");
+               nmi_panic(regs, "Unrecoverable System Reset");
 
        if (!nested)
                nmi_exit();
@@ -608,8 +652,10 @@ int machine_check_generic(struct pt_regs *regs)
 
 void machine_check_exception(struct pt_regs *regs)
 {
-       enum ctx_state prev_state = exception_enter();
        int recover = 0;
+       bool nested = in_nmi();
+       if (!nested)
+               nmi_enter();
 
        /* 64s accounts the mce in machine_check_early when in HVMODE */
        if (!IS_ENABLED(CONFIG_PPC_BOOK3S_64) || !cpu_has_feature(CPU_FTR_HVMODE))
@@ -641,10 +687,11 @@ void machine_check_exception(struct pt_regs *regs)
 
        /* Must die if the interrupt is not recoverable */
        if (!(regs->msr & MSR_RI))
-               panic("Unrecoverable Machine check");
+               nmi_panic(regs, "Unrecoverable Machine check");
 
 bail:
-       exception_exit(prev_state);
+       if (!nested)
+               nmi_exit();
 }
 
 void SMIException(struct pt_regs *regs)