aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2014-08-06 19:09:10 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-06 21:01:24 -0400
commit5874af2003b1aaaa053128d655710140e3187226 (patch)
tree35ecb809f6fa117b824880fbf05e4f5d5bed902c /kernel
parent249771b8307e7a91659d8b273f8b70d48c3a7bfc (diff)
printk: enable interrupts before calling console_trylock_for_printk()
We need interrupts disabled when calling console_trylock_for_printk() only so that cpu id we pass to can_use_console() remains valid (for other things console_sem provides all the exclusion we need and deadlocks on console_sem due to interrupts are impossible because we use down_trylock()). However if we are rescheduled, we are guaranteed to run on an online cpu so we can easily just get the cpu id in can_use_console(). We can lose a bit of performance when we enable interrupts in vprintk_emit() and then disable them again in console_unlock() but OTOH it can somewhat reduce interrupt latency caused by console_unlock(). We differ from (reverted) commit 939f04bec1a4 in that we avoid calling console_unlock() from vprintk_emit() with lockdep enabled as that has unveiled quite some bugs leading to system freezes during boot (e.g. https://lkml.org/lkml/2014/5/30/242, https://lkml.org/lkml/2014/6/28/521). Signed-off-by: Jan Kara <jack@suse.cz> Tested-by: Andreas Bombe <aeb@debian.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/printk/printk.c31
1 files changed, 21 insertions, 10 deletions
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 5eb0e6c800bb..df202fe0974a 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1450,10 +1450,9 @@ static int have_callable_console(void)
1450/* 1450/*
1451 * Can we actually use the console at this time on this cpu? 1451 * Can we actually use the console at this time on this cpu?
1452 * 1452 *
1453 * Console drivers may assume that per-cpu resources have 1453 * Console drivers may assume that per-cpu resources have been allocated. So
1454 * been allocated. So unless they're explicitly marked as 1454 * unless they're explicitly marked as being able to cope (CON_ANYTIME) don't
1455 * being able to cope (CON_ANYTIME) don't call them until 1455 * call them until this CPU is officially up.
1456 * this CPU is officially up.
1457 */ 1456 */
1458static inline int can_use_console(unsigned int cpu) 1457static inline int can_use_console(unsigned int cpu)
1459{ 1458{
@@ -1466,8 +1465,10 @@ static inline int can_use_console(unsigned int cpu)
1466 * console_lock held, and 'console_locked' set) if it 1465 * console_lock held, and 'console_locked' set) if it
1467 * is successful, false otherwise. 1466 * is successful, false otherwise.
1468 */ 1467 */
1469static int console_trylock_for_printk(unsigned int cpu) 1468static int console_trylock_for_printk(void)
1470{ 1469{
1470 unsigned int cpu = smp_processor_id();
1471
1471 if (!console_trylock()) 1472 if (!console_trylock())
1472 return 0; 1473 return 0;
1473 /* 1474 /*
@@ -1642,7 +1643,8 @@ asmlinkage int vprintk_emit(int facility, int level,
1642 */ 1643 */
1643 if (!oops_in_progress && !lockdep_recursing(current)) { 1644 if (!oops_in_progress && !lockdep_recursing(current)) {
1644 recursion_bug = 1; 1645 recursion_bug = 1;
1645 goto out_restore_irqs; 1646 local_irq_restore(flags);
1647 return 0;
1646 } 1648 }
1647 zap_locks(); 1649 zap_locks();
1648 } 1650 }
@@ -1750,21 +1752,30 @@ asmlinkage int vprintk_emit(int facility, int level,
1750 1752
1751 logbuf_cpu = UINT_MAX; 1753 logbuf_cpu = UINT_MAX;
1752 raw_spin_unlock(&logbuf_lock); 1754 raw_spin_unlock(&logbuf_lock);
1755 lockdep_on();
1756 local_irq_restore(flags);
1753 1757
1754 /* If called from the scheduler, we can not call up(). */ 1758 /* If called from the scheduler, we can not call up(). */
1755 if (!in_sched) { 1759 if (!in_sched) {
1760 lockdep_off();
1761 /*
1762 * Disable preemption to avoid being preempted while holding
1763 * console_sem which would prevent anyone from printing to
1764 * console
1765 */
1766 preempt_disable();
1767
1756 /* 1768 /*
1757 * Try to acquire and then immediately release the console 1769 * Try to acquire and then immediately release the console
1758 * semaphore. The release will print out buffers and wake up 1770 * semaphore. The release will print out buffers and wake up
1759 * /dev/kmsg and syslog() users. 1771 * /dev/kmsg and syslog() users.
1760 */ 1772 */
1761 if (console_trylock_for_printk(this_cpu)) 1773 if (console_trylock_for_printk())
1762 console_unlock(); 1774 console_unlock();
1775 preempt_enable();
1776 lockdep_on();
1763 } 1777 }
1764 1778
1765 lockdep_on();
1766out_restore_irqs:
1767 local_irq_restore(flags);
1768 return printed_len; 1779 return printed_len;
1769} 1780}
1770EXPORT_SYMBOL(vprintk_emit); 1781EXPORT_SYMBOL(vprintk_emit);