[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/