From: Thomas Gleixner <tglx@linutronix.de>
Date: Wed, 19 Sep 2012 14:50:37 +0200
Subject: printk: Make rt aware
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git
Git-commit: 8414727d39438575d33e6c150ade0a1e3f3a78ca
Patch-mainline: Queued in subsystem maintainer repository
References: SLE Realtime Extension
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>
Signed-off-by: Mike Galbraith <mgalbraith@suse.de>
---
kernel/printk/printk.c | 30 +++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1648,6 +1648,7 @@ static DEFINE_RAW_SPINLOCK(console_owner
static struct task_struct *console_owner;
static bool console_waiter;
+#ifndef CONFIG_PREEMPT_RT_FULL
/**
* printk_bust_locks - forcibly reset all printk-related locks
*
@@ -1724,6 +1725,7 @@ static int console_lock_spinning_disable
mutex_release(&console_lock_dep_map, 1, _THIS_IP_);
return 1;
}
+#endif
/**
* console_trylock_spinning - try to get console_lock by busy waiting
@@ -1755,6 +1757,9 @@ static int console_trylock_spinning(void
if (panic_in_progress())
return 0;
+ if (IS_ENABLED(CONFIG_PREEMPT_RT_FULL))
+ return 0;
+
printk_safe_enter_irqsave(flags);
raw_spin_lock(&console_owner_lock);
@@ -1814,6 +1819,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;
@@ -1829,6 +1835,7 @@ static void call_console_drivers(const c
else
con->write(con, text, len);
}
+ migrate_enable();
}
int printk_delay_msec __read_mostly;
@@ -2011,20 +2018,30 @@ 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();
+ preempt_disable_nort();
/*
* 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();
+ preempt_enable_nort();
}
return printed_len;
@@ -2480,6 +2497,10 @@ skip:
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
@@ -2498,6 +2519,7 @@ skip:
}
printk_safe_exit_irqrestore(flags);
+#endif
if (do_cond_resched)
cond_resched();
@@ -2527,7 +2549,9 @@ skip:
if (retry && console_trylock())
goto again;
+#ifndef CONFIG_PREEMPT_RT_FULL
out:
+#endif
if (wake_klogd)
wake_up_klogd();
}