Blob Blame History Raw
From: Petr Mladek <pmladek@suse.com>
Subject: [PATCH] printk/panic: Avoid deadlock in printk() after stopping CPUs by NMI
Patch-mainline: No, major printk rework is being discussed to avoid these duct taping patches
References: bsc#1148712

crash_smp_send_stop() is called before switching to crash kernel image
or before calling crash kernel notifiers. It uses NMI to stop all
CPUs where they are.

Any stopped CPU could be inside printk() code and cause deadlock
in later printk() calls. Try to avoid them by resetting all printk()
locks.

This approach will not help in all situations. The logbuf lock might
be in some inconsistent state. More complicated consoles might
break on some internal locks.

The most safe approach is to avoid printk() in crash dump code
and notifiers.

Signed-off-by: Petr Mladek <pmladek@suse.com>
---
 arch/x86/kernel/crash.c |    1 +
 include/linux/printk.h  |    6 ++++++
 kernel/printk/printk.c  |   16 ++++++++++++++++
 3 files changed, 23 insertions(+)

--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -196,6 +196,8 @@ devkmsg_sysctl_set_loglvl(struct ctl_tab
 
 extern void wake_up_klogd(void);
 
+void printk_bust_locks(void);
+
 char *log_buf_addr_get(void);
 u32 log_buf_len_get(void);
 void log_buf_vmcoreinfo_setup(void);
@@ -236,6 +238,10 @@ static inline void wake_up_klogd(void)
 {
 }
 
+static void printk_bust_locks(void)
+{
+}
+
 static inline char *log_buf_addr_get(void)
 {
 	return NULL;
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1572,6 +1572,22 @@ static struct task_struct *console_owner
 static bool console_waiter;
 
 /**
+ * printk_bust_locks - forcibly reset all printk-related locks
+ *
+ * This function can be used after CPUs were stopped using NMI.
+ * It is especially useful in kdump_nmi_shootdown_cpus() that
+ * uses NMI but it does not modify the online CPU mask.
+ */
+void printk_bust_locks(void)
+{
+	debug_locks_off();
+	raw_spin_lock_init(&logbuf_lock);
+	raw_spin_lock_init(&console_owner_lock);
+	console_owner = NULL;
+	console_waiter = false;
+}
+
+/**
  * console_lock_spinning_enable - mark beginning of code where another
  *	thread might safely busy wait
  *
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -137,6 +137,7 @@ static void kdump_nmi_callback(int cpu,
 void kdump_nmi_shootdown_cpus(void)
 {
 	nmi_shootdown_cpus(kdump_nmi_callback);
+	printk_bust_locks();
 
 	disable_local_APIC();
 }