|
@@ -61,6 +61,8 @@ void __weak panic_smp_self_stop(void)
|
|
|
cpu_relax();
|
|
|
}
|
|
|
|
|
|
+atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID);
|
|
|
+
|
|
|
/**
|
|
|
* panic - halt the system
|
|
|
* @fmt: The text string to print
|
|
@@ -71,17 +73,17 @@ void __weak panic_smp_self_stop(void)
|
|
|
*/
|
|
|
void panic(const char *fmt, ...)
|
|
|
{
|
|
|
- static DEFINE_SPINLOCK(panic_lock);
|
|
|
static char buf[1024];
|
|
|
va_list args;
|
|
|
long i, i_next = 0;
|
|
|
int state = 0;
|
|
|
+ int old_cpu, this_cpu;
|
|
|
|
|
|
/*
|
|
|
* Disable local interrupts. This will prevent panic_smp_self_stop
|
|
|
* from deadlocking the first cpu that invokes the panic, since
|
|
|
* there is nothing to prevent an interrupt handler (that runs
|
|
|
- * after the panic_lock is acquired) from invoking panic again.
|
|
|
+ * after setting panic_cpu) from invoking panic() again.
|
|
|
*/
|
|
|
local_irq_disable();
|
|
|
|
|
@@ -94,8 +96,16 @@ void panic(const char *fmt, ...)
|
|
|
* multiple parallel invocations of panic, all other CPUs either
|
|
|
* stop themself or will wait until they are stopped by the 1st CPU
|
|
|
* with smp_send_stop().
|
|
|
+ *
|
|
|
+ * `old_cpu == PANIC_CPU_INVALID' means this is the 1st CPU which
|
|
|
+ * comes here, so go ahead.
|
|
|
+ * `old_cpu == this_cpu' means we came from nmi_panic() which sets
|
|
|
+ * panic_cpu to this CPU. In this case, this is also the 1st CPU.
|
|
|
*/
|
|
|
- if (!spin_trylock(&panic_lock))
|
|
|
+ this_cpu = raw_smp_processor_id();
|
|
|
+ old_cpu = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, this_cpu);
|
|
|
+
|
|
|
+ if (old_cpu != PANIC_CPU_INVALID && old_cpu != this_cpu)
|
|
|
panic_smp_self_stop();
|
|
|
|
|
|
console_verbose();
|