[Issue]

If one cpu ,which is taking a logbuf_lock or console_sem, 
receive IPI/NMI from a panicked cpu via smp_send_stop(),
the panicked cpu hangs up in subsequent kmsg_dump()/printk()
because logbuf_lock and console_sem are taken in the function calls.

This causes a console blank and users can't see panic messages.

[Solution]

this patch introduces a logic initializing logbuf_lock and console_sem
just after smp_send_stop() to avoid dead locks above.

Signed-off-by: Seiji Aguchi <seiji.agu...@hds.com>
---
 include/linux/printk.h |    5 +++++
 kernel/panic.c         |    1 +
 kernel/printk.c        |   17 +++++++++++++++++
 lib/bust_spinlocks.c   |   21 ++++++++++++++++++---
 4 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/include/linux/printk.h b/include/linux/printk.h
index 9afc01e..ffd3e55 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -139,6 +139,7 @@ extern int kptr_restrict;
 
 void log_buf_kexec_setup(void);
 void __init setup_log_buf(int early);
+void zap_locks_force(void);
 #else
 static inline __printf(1, 0)
 int vprintk(const char *s, va_list args)
@@ -172,6 +173,10 @@ static inline void log_buf_kexec_setup(void)
 static inline void setup_log_buf(int early)
 {
 }
+
+static inline void zap_locks_force(void)
+{
+}
 #endif
 
 extern void dump_stack(void) __cold;
diff --git a/kernel/panic.c b/kernel/panic.c
index e1b2822..c27e58e 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -122,6 +122,7 @@ void panic(const char *fmt, ...)
         * situation.
         */
        smp_send_stop();
+       bust_spinlocks(2);
 
        kmsg_dump(KMSG_DUMP_PANIC);
 
diff --git a/kernel/printk.c b/kernel/printk.c
index 2d607f4..a6fa638 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -1278,6 +1278,23 @@ static void call_console_drivers(int level, const char 
*text, size_t len)
 }
 
 /*
+ * Zap console related locks in panic situation.
+ * It should be called by bust_spinlocks().
+ */
+void zap_locks_force(void)
+{
+       debug_locks_off();
+
+       /* If a crash is occurring, make sure we can't deadlock */
+       if (raw_spin_is_locked(&logbuf_lock))
+               raw_spin_lock_init(&logbuf_lock);
+
+       /* And make sure that we print immediately */
+       if (is_console_locked())
+               sema_init(&console_sem, 1);
+}
+
+/*
  * Zap console related locks when oopsing. Only zap at most once
  * every 10 seconds, to leave time for slow consoles to print a
  * full oops.
diff --git a/lib/bust_spinlocks.c b/lib/bust_spinlocks.c
index 9681d54..ffa1c64 100644
--- a/lib/bust_spinlocks.c
+++ b/lib/bust_spinlocks.c
@@ -13,19 +13,34 @@
 #include <linux/wait.h>
 #include <linux/vt_kern.h>
 #include <linux/console.h>
+#include <linux/printk.h>
 
 
+/*
+ * yes = 0: make sure that messages are printed to console immediately.
+ * yes = 1: avoid a recursive lock on a single cpu in a panic case.
+ * yes = 2: avoid a deadlock after stopping cpus by smp_send_stop()
+ *          in a panic case.
+ */
 void __attribute__((weak)) bust_spinlocks(int yes)
 {
-       if (yes) {
-               ++oops_in_progress;
-       } else {
+       switch (yes) {
+       case 0:
 #ifdef CONFIG_VT
                unblank_screen();
 #endif
                console_unblank();
                if (--oops_in_progress == 0)
                        wake_up_klogd();
+               break;
+       case 1:
+               ++oops_in_progress;
+               break;
+       case 2:
+               zap_locks_force();
+               break;
+       default:
+               break;
        }
 }
 
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to