hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I991OV
--------------------------------
In the process of load testing against panic, a deadlock issue was discovered. The reason is that in the panic process, console_unlock doesn't handle the printk_context variable evenly, causing printk_context to overflow downwards, allowing vprintk_func to enter the nmi direct branch without disabling interrupt. Upon holding the logbuf_lock lock, an interrupt running wake_up_klogd_work_func was called, resulting in a deadlock.
To avoid this issue, move printk_safe_ext_irqrestore after check abandon_console_lock_in_panic().
Fixes: 06a14c5f9e7d ("printk: Drop console_sem during panic") Signed-off-by: Ye Weihua yeweihua4@huawei.com --- kernel/printk/printk.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index f52eceb3c48a..11ebe66c473a 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2426,7 +2426,7 @@ void console_unlock(void) static char text[LOG_LINE_MAX + PREFIX_MAX]; static int panic_console_dropped; unsigned long flags; - bool do_cond_resched, retry; + bool do_cond_resched, retry, locked = false;
if (console_suspended) { up_console_sem(); @@ -2469,6 +2469,7 @@ void console_unlock(void)
printk_safe_enter_irqsave(flags); raw_spin_lock(&logbuf_lock); + locked = true; if (console_seq < log_first_seq) { len = snprintf(text, sizeof(text), "** %llu printk messages dropped **\n", @@ -2520,6 +2521,7 @@ void console_unlock(void) } console_idx = log_next(console_idx); console_seq++; + locked = false; raw_spin_unlock(&logbuf_lock);
/* @@ -2539,19 +2541,20 @@ void console_unlock(void) return; }
- printk_safe_exit_irqrestore(flags); - /* Allow panic_cpu to take over the consoles safely */ if (abandon_console_lock_in_panic()) break;
+ printk_safe_exit_irqrestore(flags); + if (do_cond_resched) cond_resched(); }
console_locked = 0;
- raw_spin_unlock(&logbuf_lock); + if (likely(locked)) + raw_spin_unlock(&logbuf_lock);
up_console_sem();