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, 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();