Skip to content

Commit 13fb0f7

Browse files
brenns10pmladek
authored andcommitted
printk: Avoid livelock with heavy printk during panic
During panic(), if another CPU is writing heavily the kernel log (e.g. via /dev/kmsg), then the panic CPU may livelock writing out its messages to the console. Note when too many messages are dropped during panic and suppress further printk, except from the panic CPU. This could result in some important messages being dropped. However, messages are already being dropped, so this approach at least prevents a livelock. Reviewed-by: Petr Mladek <pmladek@suse.com> Signed-off-by: Stephen Brennan <stephen.s.brennan@oracle.com> Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org> Signed-off-by: Petr Mladek <pmladek@suse.com> Link: https://lore.kernel.org/r/20220202171821.179394-4-stephen.s.brennan@oracle.com
1 parent d515070 commit 13fb0f7

File tree

1 file changed

+15
-0
lines changed

1 file changed

+15
-0
lines changed

kernel/printk/printk.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ EXPORT_SYMBOL_GPL(console_drivers);
9393
*/
9494
int __read_mostly suppress_printk;
9595

96+
/*
97+
* During panic, heavy printk by other CPUs can delay the
98+
* panic and risk deadlock on console resources.
99+
*/
100+
int __read_mostly suppress_panic_printk;
101+
96102
#ifdef CONFIG_LOCKDEP
97103
static struct lockdep_map console_lock_dep_map = {
98104
.name = "console_lock"
@@ -2232,6 +2238,10 @@ asmlinkage int vprintk_emit(int facility, int level,
22322238
if (unlikely(suppress_printk))
22332239
return 0;
22342240

2241+
if (unlikely(suppress_panic_printk) &&
2242+
atomic_read(&panic_cpu) != raw_smp_processor_id())
2243+
return 0;
2244+
22352245
if (level == LOGLEVEL_SCHED) {
22362246
level = LOGLEVEL_DEFAULT;
22372247
in_sched = true;
@@ -2617,6 +2627,7 @@ void console_unlock(void)
26172627
{
26182628
static char ext_text[CONSOLE_EXT_LOG_MAX];
26192629
static char text[CONSOLE_LOG_MAX];
2630+
static int panic_console_dropped;
26202631
unsigned long flags;
26212632
bool do_cond_resched, retry;
26222633
struct printk_info info;
@@ -2671,6 +2682,10 @@ void console_unlock(void)
26712682
if (console_seq != r.info->seq) {
26722683
console_dropped += r.info->seq - console_seq;
26732684
console_seq = r.info->seq;
2685+
if (panic_in_progress() && panic_console_dropped++ > 10) {
2686+
suppress_panic_printk = 1;
2687+
pr_warn_once("Too many dropped messages. Suppress messages on non-panic CPUs to prevent livelock.\n");
2688+
}
26742689
}
26752690

26762691
if (suppress_message_printing(r.info->level)) {

0 commit comments

Comments
 (0)