|  | Subject: printk: Make rt aware | 
|  | From: Thomas Gleixner <tglx@linutronix.de> | 
|  | Date: Wed, 19 Sep 2012 14:50:37 +0200 | 
|  |  | 
|  | Drop the lock before calling the console driver and do not disable | 
|  | interrupts while printing to a serial console. | 
|  |  | 
|  | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | 
|  | --- | 
|  | kernel/printk/printk.c |   36 +++++++++++++++++++++++++++++++++--- | 
|  | 1 file changed, 33 insertions(+), 3 deletions(-) | 
|  |  | 
|  | --- a/kernel/printk/printk.c | 
|  | +++ b/kernel/printk/printk.c | 
|  | @@ -1606,6 +1606,7 @@ SYSCALL_DEFINE3(syslog, int, type, char | 
|  | return do_syslog(type, buf, len, SYSLOG_FROM_READER); | 
|  | } | 
|  |  | 
|  | +#ifndef CONFIG_PREEMPT_RT_FULL | 
|  | /* | 
|  | * Special console_lock variants that help to reduce the risk of soft-lockups. | 
|  | * They allow to pass console_lock to another printk() call using a busy wait. | 
|  | @@ -1746,6 +1747,15 @@ static int console_trylock_spinning(void | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | +#else | 
|  | + | 
|  | +static int console_trylock_spinning(void) | 
|  | +{ | 
|  | +	return console_trylock(); | 
|  | +} | 
|  | + | 
|  | +#endif | 
|  | + | 
|  | /* | 
|  | * Call the console drivers, asking them to write out | 
|  | * log_buf[start] to log_buf[end - 1]. | 
|  | @@ -1761,6 +1771,7 @@ static void call_console_drivers(const c | 
|  | if (!console_drivers) | 
|  | return; | 
|  |  | 
|  | +	migrate_disable(); | 
|  | for_each_console(con) { | 
|  | if (exclusive_console && con != exclusive_console) | 
|  | continue; | 
|  | @@ -1776,6 +1787,7 @@ static void call_console_drivers(const c | 
|  | else | 
|  | con->write(con, text, len); | 
|  | } | 
|  | +	migrate_enable(); | 
|  | } | 
|  |  | 
|  | int printk_delay_msec __read_mostly; | 
|  | @@ -1958,20 +1970,31 @@ asmlinkage int vprintk_emit(int facility | 
|  |  | 
|  | /* If called from the scheduler, we can not call up(). */ | 
|  | if (!in_sched) { | 
|  | +		int may_trylock = 1; | 
|  | + | 
|  | +#ifdef CONFIG_PREEMPT_RT_FULL | 
|  | +		/* | 
|  | +		 * we can't take a sleeping lock with IRQs or preeption disabled | 
|  | +		 * so we can't print in these contexts | 
|  | +		 */ | 
|  | +		if (!(preempt_count() == 0 && !irqs_disabled())) | 
|  | +			may_trylock = 0; | 
|  | +#endif | 
|  | + | 
|  | /* | 
|  | * Disable preemption to avoid being preempted while holding | 
|  | * console_sem which would prevent anyone from printing to | 
|  | * console | 
|  | */ | 
|  | -		preempt_disable(); | 
|  | +		migrate_disable(); | 
|  | /* | 
|  | * Try to acquire and then immediately release the console | 
|  | * semaphore.  The release will print out buffers and wake up | 
|  | * /dev/kmsg and syslog() users. | 
|  | */ | 
|  | -		if (console_trylock_spinning()) | 
|  | +		if (may_trylock && console_trylock_spinning()) | 
|  | console_unlock(); | 
|  | -		preempt_enable(); | 
|  | +		migrate_enable(); | 
|  | } | 
|  |  | 
|  | return printed_len; | 
|  | @@ -2429,6 +2452,10 @@ void console_unlock(void) | 
|  | console_seq++; | 
|  | raw_spin_unlock(&logbuf_lock); | 
|  |  | 
|  | +#ifdef CONFIG_PREEMPT_RT_FULL | 
|  | +		printk_safe_exit_irqrestore(flags); | 
|  | +		call_console_drivers(ext_text, ext_len, text, len); | 
|  | +#else | 
|  | /* | 
|  | * While actively printing out messages, if another printk() | 
|  | * were to occur on another CPU, it may wait for this one to | 
|  | @@ -2447,6 +2474,7 @@ void console_unlock(void) | 
|  | } | 
|  |  | 
|  | printk_safe_exit_irqrestore(flags); | 
|  | +#endif | 
|  |  | 
|  | if (do_cond_resched) | 
|  | cond_resched(); | 
|  | @@ -2476,7 +2504,9 @@ void console_unlock(void) | 
|  | if (retry && console_trylock()) | 
|  | goto again; | 
|  |  | 
|  | +#ifndef CONFIG_PREEMPT_RT_FULL | 
|  | out: | 
|  | +#endif | 
|  | if (wake_klogd) | 
|  | wake_up_klogd(); | 
|  | } |