aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/printk.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/printk.c')
-rw-r--r--kernel/printk.c87
1 files changed, 61 insertions, 26 deletions
diff --git a/kernel/printk.c b/kernel/printk.c
index 19a955619294..771f5e861bcd 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -24,8 +24,8 @@
24#include <linux/console.h> 24#include <linux/console.h>
25#include <linux/init.h> 25#include <linux/init.h>
26#include <linux/module.h> 26#include <linux/module.h>
27#include <linux/moduleparam.h>
27#include <linux/interrupt.h> /* For in_interrupt() */ 28#include <linux/interrupt.h> /* For in_interrupt() */
28#include <linux/config.h>
29#include <linux/delay.h> 29#include <linux/delay.h>
30#include <linux/smp.h> 30#include <linux/smp.h>
31#include <linux/security.h> 31#include <linux/security.h>
@@ -52,7 +52,7 @@ int console_printk[4] = {
52 DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */ 52 DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */
53}; 53};
54 54
55EXPORT_SYMBOL(console_printk); 55EXPORT_UNUSED_SYMBOL(console_printk); /* June 2006 */
56 56
57/* 57/*
58 * Low lever drivers may need that to know if they can schedule in 58 * Low lever drivers may need that to know if they can schedule in
@@ -327,7 +327,9 @@ static void __call_console_drivers(unsigned long start, unsigned long end)
327 struct console *con; 327 struct console *con;
328 328
329 for (con = console_drivers; con; con = con->next) { 329 for (con = console_drivers; con; con = con->next) {
330 if ((con->flags & CON_ENABLED) && con->write) 330 if ((con->flags & CON_ENABLED) && con->write &&
331 (cpu_online(smp_processor_id()) ||
332 (con->flags & CON_ANYTIME)))
331 con->write(con, &LOG_BUF(start), end - start); 333 con->write(con, &LOG_BUF(start), end - start);
332 } 334 }
333} 335}
@@ -437,6 +439,7 @@ static int printk_time = 1;
437#else 439#else
438static int printk_time = 0; 440static int printk_time = 0;
439#endif 441#endif
442module_param(printk_time, int, S_IRUGO | S_IWUSR);
440 443
441static int __init printk_time_setup(char *str) 444static int __init printk_time_setup(char *str)
442{ 445{
@@ -453,6 +456,18 @@ __attribute__((weak)) unsigned long long printk_clock(void)
453 return sched_clock(); 456 return sched_clock();
454} 457}
455 458
459/* Check if we have any console registered that can be called early in boot. */
460static int have_callable_console(void)
461{
462 struct console *con;
463
464 for (con = console_drivers; con; con = con->next)
465 if (con->flags & CON_ANYTIME)
466 return 1;
467
468 return 0;
469}
470
456/** 471/**
457 * printk - print a kernel message 472 * printk - print a kernel message
458 * @fmt: format string 473 * @fmt: format string
@@ -503,7 +518,9 @@ asmlinkage int vprintk(const char *fmt, va_list args)
503 zap_locks(); 518 zap_locks();
504 519
505 /* This stops the holder of console_sem just where we want him */ 520 /* This stops the holder of console_sem just where we want him */
506 spin_lock_irqsave(&logbuf_lock, flags); 521 local_irq_save(flags);
522 lockdep_off();
523 spin_lock(&logbuf_lock);
507 printk_cpu = smp_processor_id(); 524 printk_cpu = smp_processor_id();
508 525
509 /* Emit the output into the temporary buffer */ 526 /* Emit the output into the temporary buffer */
@@ -566,27 +583,31 @@ asmlinkage int vprintk(const char *fmt, va_list args)
566 log_level_unknown = 1; 583 log_level_unknown = 1;
567 } 584 }
568 585
569 if (!cpu_online(smp_processor_id())) { 586 if (!down_trylock(&console_sem)) {
570 /* 587 /*
571 * Some console drivers may assume that per-cpu resources have 588 * We own the drivers. We can drop the spinlock and
572 * been allocated. So don't allow them to be called by this 589 * let release_console_sem() print the text, maybe ...
573 * CPU until it is officially up. We shouldn't be calling into
574 * random console drivers on a CPU which doesn't exist yet..
575 */ 590 */
576 printk_cpu = UINT_MAX;
577 spin_unlock_irqrestore(&logbuf_lock, flags);
578 goto out;
579 }
580 if (!down_trylock(&console_sem)) {
581 console_locked = 1; 591 console_locked = 1;
592 printk_cpu = UINT_MAX;
593 spin_unlock(&logbuf_lock);
594
582 /* 595 /*
583 * We own the drivers. We can drop the spinlock and let 596 * Console drivers may assume that per-cpu resources have
584 * release_console_sem() print the text 597 * been allocated. So unless they're explicitly marked as
598 * being able to cope (CON_ANYTIME) don't call them until
599 * this CPU is officially up.
585 */ 600 */
586 printk_cpu = UINT_MAX; 601 if (cpu_online(smp_processor_id()) || have_callable_console()) {
587 spin_unlock_irqrestore(&logbuf_lock, flags); 602 console_may_schedule = 0;
588 console_may_schedule = 0; 603 release_console_sem();
589 release_console_sem(); 604 } else {
605 /* Release by hand to avoid flushing the buffer. */
606 console_locked = 0;
607 up(&console_sem);
608 }
609 lockdep_on();
610 local_irq_restore(flags);
590 } else { 611 } else {
591 /* 612 /*
592 * Someone else owns the drivers. We drop the spinlock, which 613 * Someone else owns the drivers. We drop the spinlock, which
@@ -594,9 +615,11 @@ asmlinkage int vprintk(const char *fmt, va_list args)
594 * console drivers with the output which we just produced. 615 * console drivers with the output which we just produced.
595 */ 616 */
596 printk_cpu = UINT_MAX; 617 printk_cpu = UINT_MAX;
597 spin_unlock_irqrestore(&logbuf_lock, flags); 618 spin_unlock(&logbuf_lock);
619 lockdep_on();
620 local_irq_restore(flags);
598 } 621 }
599out: 622
600 preempt_enable(); 623 preempt_enable();
601 return printed_len; 624 return printed_len;
602} 625}
@@ -698,6 +721,7 @@ int __init add_preferred_console(char *name, int idx, char *options)
698 return 0; 721 return 0;
699} 722}
700 723
724#ifndef CONFIG_DISABLE_CONSOLE_SUSPEND
701/** 725/**
702 * suspend_console - suspend the console subsystem 726 * suspend_console - suspend the console subsystem
703 * 727 *
@@ -705,6 +729,7 @@ int __init add_preferred_console(char *name, int idx, char *options)
705 */ 729 */
706void suspend_console(void) 730void suspend_console(void)
707{ 731{
732 printk("Suspending console(s)\n");
708 acquire_console_sem(); 733 acquire_console_sem();
709 console_suspended = 1; 734 console_suspended = 1;
710} 735}
@@ -714,6 +739,7 @@ void resume_console(void)
714 console_suspended = 0; 739 console_suspended = 0;
715 release_console_sem(); 740 release_console_sem();
716} 741}
742#endif /* CONFIG_DISABLE_CONSOLE_SUSPEND */
717 743
718/** 744/**
719 * acquire_console_sem - lock the console system for exclusive use. 745 * acquire_console_sem - lock the console system for exclusive use.
@@ -750,7 +776,7 @@ int is_console_locked(void)
750{ 776{
751 return console_locked; 777 return console_locked;
752} 778}
753EXPORT_SYMBOL(is_console_locked); 779EXPORT_UNUSED_SYMBOL(is_console_locked); /* June 2006 */
754 780
755/** 781/**
756 * release_console_sem - unlock the console system 782 * release_console_sem - unlock the console system
@@ -776,6 +802,9 @@ void release_console_sem(void)
776 up(&secondary_console_sem); 802 up(&secondary_console_sem);
777 return; 803 return;
778 } 804 }
805
806 console_may_schedule = 0;
807
779 for ( ; ; ) { 808 for ( ; ; ) {
780 spin_lock_irqsave(&logbuf_lock, flags); 809 spin_lock_irqsave(&logbuf_lock, flags);
781 wake_klogd |= log_start - log_end; 810 wake_klogd |= log_start - log_end;
@@ -789,11 +818,17 @@ void release_console_sem(void)
789 local_irq_restore(flags); 818 local_irq_restore(flags);
790 } 819 }
791 console_locked = 0; 820 console_locked = 0;
792 console_may_schedule = 0;
793 up(&console_sem); 821 up(&console_sem);
794 spin_unlock_irqrestore(&logbuf_lock, flags); 822 spin_unlock_irqrestore(&logbuf_lock, flags);
795 if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait)) 823 if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait)) {
796 wake_up_interruptible(&log_wait); 824 /*
825 * If we printk from within the lock dependency code,
826 * from within the scheduler code, then do not lock
827 * up due to self-recursion:
828 */
829 if (!lockdep_internal())
830 wake_up_interruptible(&log_wait);
831 }
797} 832}
798EXPORT_SYMBOL(release_console_sem); 833EXPORT_SYMBOL(release_console_sem);
799 834