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

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;
 
 /* Control whether printing to console must be synchronous. */
 static bool __read_mostly printk_sync = false;
+/*
+ * 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_sync && printk_kthread;
+	return !printk_sync && printk_kthread && !force_printk_sync;
 }
 
 /* Return log buffer address */
@@ -1935,6 +1940,7 @@ static size_t cont_print_text(char *text
 
 /* Still needs to be defined for users */
 DEFINE_PER_CPU(printk_func_t, printk_func);
+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;
 	printk("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();