Skip to content

Commit

Permalink
printk: wake waiters for safe and NMI contexts
Browse files Browse the repository at this point in the history
When printk() is called from safe or NMI contexts, it will directly
store the record (vprintk_store()) and then defer the console output.
However, defer_console_output() only causes console printing and does
not wake any waiters of new records.

Wake waiters from defer_console_output() so that they also are aware
of the new records from safe and NMI contexts.

Fixes: 03fc7f9 ("printk/nmi: Prevent deadlock when accessing the main log buffer in NMI")
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20220421212250.565456-6-john.ogness@linutronix.de
  • Loading branch information
John Ogness authored and Petr Mladek committed Apr 22, 2022
1 parent 938ba40 commit 5341b93
Showing 1 changed file with 16 additions and 12 deletions.
28 changes: 16 additions & 12 deletions kernel/printk/printk.c
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
* prepare_to_wait_event() pairs with the full memory barrier
* within wq_has_sleeper().
*
* This pairs with wake_up_klogd:A.
* This pairs with __wake_up_klogd:A.
*/
ret = wait_event_interruptible(log_wait,
prb_read_valid(prb,
Expand Down Expand Up @@ -1532,7 +1532,7 @@ static int syslog_print(char __user *buf, int size)
* prepare_to_wait_event() pairs with the full memory barrier
* within wq_has_sleeper().
*
* This pairs with wake_up_klogd:A.
* This pairs with __wake_up_klogd:A.
*/
len = wait_event_interruptible(log_wait,
prb_read_valid(prb, seq, NULL)); /* LMM(syslog_print:A) */
Expand Down Expand Up @@ -3332,7 +3332,7 @@ static void wake_up_klogd_work_func(struct irq_work *irq_work)
static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) =
IRQ_WORK_INIT_LAZY(wake_up_klogd_work_func);

void wake_up_klogd(void)
static void __wake_up_klogd(int val)
{
if (!printk_percpu_data_ready())
return;
Expand All @@ -3349,22 +3349,26 @@ void wake_up_klogd(void)
*
* This pairs with devkmsg_read:A and syslog_print:A.
*/
if (wq_has_sleeper(&log_wait)) { /* LMM(wake_up_klogd:A) */
this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
if (wq_has_sleeper(&log_wait) || /* LMM(__wake_up_klogd:A) */
(val & PRINTK_PENDING_OUTPUT)) {
this_cpu_or(printk_pending, val);
irq_work_queue(this_cpu_ptr(&wake_up_klogd_work));
}
preempt_enable();
}

void defer_console_output(void)
void wake_up_klogd(void)
{
if (!printk_percpu_data_ready())
return;
__wake_up_klogd(PRINTK_PENDING_WAKEUP);
}

preempt_disable();
this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT);
irq_work_queue(this_cpu_ptr(&wake_up_klogd_work));
preempt_enable();
void defer_console_output(void)
{
/*
* New messages may have been added directly to the ringbuffer
* using vprintk_store(), so wake any waiters as well.
*/
__wake_up_klogd(PRINTK_PENDING_WAKEUP | PRINTK_PENDING_OUTPUT);
}

void printk_trigger_flush(void)
Expand Down

0 comments on commit 5341b93

Please sign in to comment.