diff options
author | Jan Kara <jack@suse.cz> | 2014-08-06 19:09:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-06 21:01:24 -0400 |
commit | 5874af2003b1aaaa053128d655710140e3187226 (patch) | |
tree | 35ecb809f6fa117b824880fbf05e4f5d5bed902c /kernel | |
parent | 249771b8307e7a91659d8b273f8b70d48c3a7bfc (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.c | 31 |
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 | */ |
1458 | static inline int can_use_console(unsigned int cpu) | 1457 | static 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 | */ |
1469 | static int console_trylock_for_printk(unsigned int cpu) | 1468 | static 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(); | ||
1766 | out_restore_irqs: | ||
1767 | local_irq_restore(flags); | ||
1768 | return printed_len; | 1779 | return printed_len; |
1769 | } | 1780 | } |
1770 | EXPORT_SYMBOL(vprintk_emit); | 1781 | EXPORT_SYMBOL(vprintk_emit); |