lkml.org 
[lkml]   [2012]   [Nov]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH] Avoid dead lock of console related locks in panic case
Date
[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.aguchi@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


\
 
 \ /
  Last update: 2012-11-30 20:01    [W:0.383 / U:2.808 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site