diff --git a/kernel/printk.c b/kernel/printk.c index 751e7b84e9e3..37dff3429adb 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -1244,7 +1244,7 @@ void console_unlock(void) { unsigned long flags; unsigned _con_start, _log_end; - unsigned wake_klogd = 0; + unsigned wake_klogd = 0, retry = 0; if (console_suspended) { up(&console_sem); @@ -1253,6 +1253,7 @@ void console_unlock(void) console_may_schedule = 0; +again: for ( ; ; ) { spin_lock_irqsave(&logbuf_lock, flags); wake_klogd |= log_start - log_end; @@ -1273,8 +1274,23 @@ void console_unlock(void) if (unlikely(exclusive_console)) exclusive_console = NULL; - spin_unlock_irqrestore(&logbuf_lock, flags); + spin_unlock(&logbuf_lock); + up(&console_sem); + + /* + * Someone could have filled up the buffer again, so re-check if there's + * something to flush. In case we cannot trylock the console_sem again, + * there's a new owner and the console_unlock() from them will do the + * flush, no worries. + */ + spin_lock(&logbuf_lock); + if (con_start != log_end) + retry = 1; + spin_unlock_irqrestore(&logbuf_lock, flags); + if (retry && console_trylock()) + goto again; + if (wake_klogd) wake_up_klogd(); }