[PATCH 1/3] printk: introduce console_reset_on_panic() function

From: Sergey Senozhatsky
Date: Sun Jan 31 2016 - 07:32:38 EST


CPU stop IPI issued from panic() on CPUA, can leave console_sem locked
on CPUB if that cpu was holding the console_sem lock at the time when
IPI arrived. console_flush_on_panic() is trying to workaround it by
ignoring the return status of console_trylock() and unconditionally
executing console_unlock().

console_unlock() has a dependency on at least one more
lock - `logbuf_lock', which can be corrupted, for example, thus
console_unlock() may not be able to print anything afterall.

Introduce console_reset_on_panic() function to zap (re-init) printk
locks and call this function from panic().

WARNING
=======
This must be improved. console_reset_on_panic() is called before
smp_send_stop(), so:
a) we can have several CPU looping in console_unlock(), which is not
so critical.
b) we can re-init logbuf_lock while other CPU is holding it. Which
is more serious and needs to fixed.

The reason why console_reset_on_panic() is called this early is that
panicing CPU does pr_emerg("Kernel panic...") and dump_stack()
before it sends out smp_send_stop(). So if console_sem or logbug_lock,
or some console device driver lock is/are corrupted then panic() may
never smp_send_stop().

Not-Yet-Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@xxxxxxxxx>
---
include/linux/console.h | 1 +
kernel/panic.c | 1 +
kernel/printk/printk.c | 5 +++++
3 files changed, 7 insertions(+)

diff --git a/include/linux/console.h b/include/linux/console.h
index ea731af..6edc2ea 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -151,6 +151,7 @@ extern void console_unlock(void);
extern void console_conditional_schedule(void);
extern void console_unblank(void);
extern void console_flush_on_panic(void);
+extern void console_reset_on_panic(void);
extern struct tty_driver *console_device(int *);
extern void console_stop(struct console *);
extern void console_start(struct console *);
diff --git a/kernel/panic.c b/kernel/panic.c
index d96469d..71d43f6 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -119,6 +119,7 @@ void panic(const char *fmt, ...)

console_verbose();
bust_spinlocks(1);
+ console_reset_on_panic();
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 097ca8b..34642f7 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2394,6 +2394,11 @@ void console_flush_on_panic(void)
console_unlock();
}

+void console_reset_on_panic(void)
+{
+ zap_locks();
+}
+
/*
* Return the console tty driver structure and its associated index
*/
--
2.7.0