diff options
Diffstat (limited to 'kernel/printk.c')
| -rw-r--r-- | kernel/printk.c | 24 | 
1 files changed, 21 insertions, 3 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 35185392173f..37dff3429adb 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -782,7 +782,7 @@ static inline int can_use_console(unsigned int cpu)  static int console_trylock_for_printk(unsigned int cpu)  	__releases(&logbuf_lock)  { -	int retval = 0; +	int retval = 0, wake = 0;  	if (console_trylock()) {  		retval = 1; @@ -795,12 +795,14 @@ static int console_trylock_for_printk(unsigned int cpu)  		 */  		if (!can_use_console(cpu)) {  			console_locked = 0; -			up(&console_sem); +			wake = 1;  			retval = 0;  		}  	}  	printk_cpu = UINT_MAX;  	spin_unlock(&logbuf_lock); +	if (wake) +		up(&console_sem);  	return retval;  }  static const char recursion_bug_msg [] = @@ -1242,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); @@ -1251,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; @@ -1271,8 +1274,23 @@ void console_unlock(void)  	if (unlikely(exclusive_console))  		exclusive_console = NULL; +	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();  }  |