Skip to content

Commit 5341b93

Browse files
jognesspmladek
authored andcommitted
printk: wake waiters for safe and NMI contexts
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 <[email protected]> Reviewed-by: Petr Mladek <[email protected]> Signed-off-by: Petr Mladek <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 938ba40 commit 5341b93

File tree

1 file changed

+16
-12
lines changed

1 file changed

+16
-12
lines changed

kernel/printk/printk.c

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
754754
* prepare_to_wait_event() pairs with the full memory barrier
755755
* within wq_has_sleeper().
756756
*
757-
* This pairs with wake_up_klogd:A.
757+
* This pairs with __wake_up_klogd:A.
758758
*/
759759
ret = wait_event_interruptible(log_wait,
760760
prb_read_valid(prb,
@@ -1532,7 +1532,7 @@ static int syslog_print(char __user *buf, int size)
15321532
* prepare_to_wait_event() pairs with the full memory barrier
15331533
* within wq_has_sleeper().
15341534
*
1535-
* This pairs with wake_up_klogd:A.
1535+
* This pairs with __wake_up_klogd:A.
15361536
*/
15371537
len = wait_event_interruptible(log_wait,
15381538
prb_read_valid(prb, seq, NULL)); /* LMM(syslog_print:A) */
@@ -3332,7 +3332,7 @@ static void wake_up_klogd_work_func(struct irq_work *irq_work)
33323332
static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) =
33333333
IRQ_WORK_INIT_LAZY(wake_up_klogd_work_func);
33343334

3335-
void wake_up_klogd(void)
3335+
static void __wake_up_klogd(int val)
33363336
{
33373337
if (!printk_percpu_data_ready())
33383338
return;
@@ -3349,22 +3349,26 @@ void wake_up_klogd(void)
33493349
*
33503350
* This pairs with devkmsg_read:A and syslog_print:A.
33513351
*/
3352-
if (wq_has_sleeper(&log_wait)) { /* LMM(wake_up_klogd:A) */
3353-
this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
3352+
if (wq_has_sleeper(&log_wait) || /* LMM(__wake_up_klogd:A) */
3353+
(val & PRINTK_PENDING_OUTPUT)) {
3354+
this_cpu_or(printk_pending, val);
33543355
irq_work_queue(this_cpu_ptr(&wake_up_klogd_work));
33553356
}
33563357
preempt_enable();
33573358
}
33583359

3359-
void defer_console_output(void)
3360+
void wake_up_klogd(void)
33603361
{
3361-
if (!printk_percpu_data_ready())
3362-
return;
3362+
__wake_up_klogd(PRINTK_PENDING_WAKEUP);
3363+
}
33633364

3364-
preempt_disable();
3365-
this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT);
3366-
irq_work_queue(this_cpu_ptr(&wake_up_klogd_work));
3367-
preempt_enable();
3365+
void defer_console_output(void)
3366+
{
3367+
/*
3368+
* New messages may have been added directly to the ringbuffer
3369+
* using vprintk_store(), so wake any waiters as well.
3370+
*/
3371+
__wake_up_klogd(PRINTK_PENDING_WAKEUP | PRINTK_PENDING_OUTPUT);
33683372
}
33693373

33703374
void printk_trigger_flush(void)

0 commit comments

Comments
 (0)