Blob Blame History Raw
From: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
Subject: printk: Fix possible printk recursion during suspend
Patch-mainline: Not yet, still being discussed upstream
References: bsc#995541, bsc#1174146

When suspending with no_console_suspend command line option the timer code
will complain (with a WARN_ON) about being called when suspended because a
wake_up() happening from async printk code ends up calling in the timer code.
This results in a recursion back into printk code and subsequently a deadlock.

Fix the problem by switching to synchronous printk during suspend.

Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>

---
 kernel/printk/printk.c |   12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -287,6 +287,11 @@ static u32 log_buf_len = __LOG_BUF_LEN;
 static char *log_buf = __log_buf;
 static u32 log_buf_len = __LOG_BUF_LEN;
 
+/*
+ * Force sync printk mode during suspend/kexec, regardless whether
+ * console_suspend_enabled permits console suspend.
+ */
+static bool __read_mostly force_printk_sync;
 /* Printing kthread for async printk */
 static struct task_struct *printk_kthread;
 /* When `true' printing thread has messages to print */
@@ -294,7 +299,7 @@ static bool printk_kthread_need_flush_co
 
 static inline bool can_printk_async(void)
 {
-	return printk_kthread;
+	return printk_kthread && !force_printk_sync;
 }
 
 /*
@@ -1935,6 +1940,9 @@ static size_t cont_print_text(char *text
 static size_t msg_print_text(const struct printk_log *msg, bool syslog,
 			     bool time, char *buf, size_t size) { return 0; }
 static bool suppress_message_printing(int level) { return false; }
+
+/* Still needs to be defined for users */
+static bool __read_mostly force_printk_sync;
 
 #endif /* CONFIG_PRINTK */
 
@@ -2071,6 +2077,8 @@ MODULE_PARM_DESC(console_suspend, "suspe
  */
 void suspend_console(void)
 {
+	force_printk_sync = true;
+
 	if (!console_suspend_enabled)
 		return;
 	pr_info("Suspending console(s) (use no_console_suspend to debug)\n");
@@ -2081,6 +2089,8 @@ void suspend_console(void)
 
 void resume_console(void)
 {
+	force_printk_sync = false;
+
 	if (!console_suspend_enabled)
 		return;
 	down_console_sem();