diff options
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 108 |
1 files changed, 82 insertions, 26 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index c056f3324432..65ca0688f86f 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 | ||
55 | EXPORT_SYMBOL(console_printk); | 55 | EXPORT_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 |
@@ -67,6 +67,7 @@ EXPORT_SYMBOL(oops_in_progress); | |||
67 | * driver system. | 67 | * driver system. |
68 | */ | 68 | */ |
69 | static DECLARE_MUTEX(console_sem); | 69 | static DECLARE_MUTEX(console_sem); |
70 | static DECLARE_MUTEX(secondary_console_sem); | ||
70 | struct console *console_drivers; | 71 | struct console *console_drivers; |
71 | /* | 72 | /* |
72 | * This is used for debugging the mess that is the VT code by | 73 | * This is used for debugging the mess that is the VT code by |
@@ -76,7 +77,7 @@ struct console *console_drivers; | |||
76 | * path in the console code where we end up in places I want | 77 | * path in the console code where we end up in places I want |
77 | * locked without the console sempahore held | 78 | * locked without the console sempahore held |
78 | */ | 79 | */ |
79 | static int console_locked; | 80 | static int console_locked, console_suspended; |
80 | 81 | ||
81 | /* | 82 | /* |
82 | * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars | 83 | * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars |
@@ -326,7 +327,9 @@ static void __call_console_drivers(unsigned long start, unsigned long end) | |||
326 | struct console *con; | 327 | struct console *con; |
327 | 328 | ||
328 | for (con = console_drivers; con; con = con->next) { | 329 | for (con = console_drivers; con; con = con->next) { |
329 | 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))) | ||
330 | con->write(con, &LOG_BUF(start), end - start); | 333 | con->write(con, &LOG_BUF(start), end - start); |
331 | } | 334 | } |
332 | } | 335 | } |
@@ -436,6 +439,7 @@ static int printk_time = 1; | |||
436 | #else | 439 | #else |
437 | static int printk_time = 0; | 440 | static int printk_time = 0; |
438 | #endif | 441 | #endif |
442 | module_param(printk_time, int, S_IRUGO | S_IWUSR); | ||
439 | 443 | ||
440 | static int __init printk_time_setup(char *str) | 444 | static int __init printk_time_setup(char *str) |
441 | { | 445 | { |
@@ -452,6 +456,18 @@ __attribute__((weak)) unsigned long long printk_clock(void) | |||
452 | return sched_clock(); | 456 | return sched_clock(); |
453 | } | 457 | } |
454 | 458 | ||
459 | /* Check if we have any console registered that can be called early in boot. */ | ||
460 | static 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 | |||
455 | /** | 471 | /** |
456 | * printk - print a kernel message | 472 | * printk - print a kernel message |
457 | * @fmt: format string | 473 | * @fmt: format string |
@@ -502,7 +518,9 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
502 | zap_locks(); | 518 | zap_locks(); |
503 | 519 | ||
504 | /* 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 */ |
505 | spin_lock_irqsave(&logbuf_lock, flags); | 521 | local_irq_save(flags); |
522 | lockdep_off(); | ||
523 | spin_lock(&logbuf_lock); | ||
506 | printk_cpu = smp_processor_id(); | 524 | printk_cpu = smp_processor_id(); |
507 | 525 | ||
508 | /* Emit the output into the temporary buffer */ | 526 | /* Emit the output into the temporary buffer */ |
@@ -565,27 +583,31 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
565 | log_level_unknown = 1; | 583 | log_level_unknown = 1; |
566 | } | 584 | } |
567 | 585 | ||
568 | if (!cpu_online(smp_processor_id())) { | 586 | if (!down_trylock(&console_sem)) { |
569 | /* | 587 | /* |
570 | * Some console drivers may assume that per-cpu resources have | 588 | * We own the drivers. We can drop the spinlock and |
571 | * been allocated. So don't allow them to be called by this | 589 | * let release_console_sem() print the text, maybe ... |
572 | * CPU until it is officially up. We shouldn't be calling into | ||
573 | * random console drivers on a CPU which doesn't exist yet.. | ||
574 | */ | 590 | */ |
575 | printk_cpu = UINT_MAX; | ||
576 | spin_unlock_irqrestore(&logbuf_lock, flags); | ||
577 | goto out; | ||
578 | } | ||
579 | if (!down_trylock(&console_sem)) { | ||
580 | console_locked = 1; | 591 | console_locked = 1; |
592 | printk_cpu = UINT_MAX; | ||
593 | spin_unlock(&logbuf_lock); | ||
594 | |||
581 | /* | 595 | /* |
582 | * We own the drivers. We can drop the spinlock and let | 596 | * Console drivers may assume that per-cpu resources have |
583 | * 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. | ||
584 | */ | 600 | */ |
585 | printk_cpu = UINT_MAX; | 601 | if (cpu_online(smp_processor_id()) || have_callable_console()) { |
586 | spin_unlock_irqrestore(&logbuf_lock, flags); | 602 | console_may_schedule = 0; |
587 | console_may_schedule = 0; | 603 | release_console_sem(); |
588 | 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); | ||
589 | } else { | 611 | } else { |
590 | /* | 612 | /* |
591 | * Someone else owns the drivers. We drop the spinlock, which | 613 | * Someone else owns the drivers. We drop the spinlock, which |
@@ -593,9 +615,11 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
593 | * console drivers with the output which we just produced. | 615 | * console drivers with the output which we just produced. |
594 | */ | 616 | */ |
595 | printk_cpu = UINT_MAX; | 617 | printk_cpu = UINT_MAX; |
596 | spin_unlock_irqrestore(&logbuf_lock, flags); | 618 | spin_unlock(&logbuf_lock); |
619 | lockdep_on(); | ||
620 | local_irq_restore(flags); | ||
597 | } | 621 | } |
598 | out: | 622 | |
599 | preempt_enable(); | 623 | preempt_enable(); |
600 | return printed_len; | 624 | return printed_len; |
601 | } | 625 | } |
@@ -698,6 +722,23 @@ int __init add_preferred_console(char *name, int idx, char *options) | |||
698 | } | 722 | } |
699 | 723 | ||
700 | /** | 724 | /** |
725 | * suspend_console - suspend the console subsystem | ||
726 | * | ||
727 | * This disables printk() while we go into suspend states | ||
728 | */ | ||
729 | void suspend_console(void) | ||
730 | { | ||
731 | acquire_console_sem(); | ||
732 | console_suspended = 1; | ||
733 | } | ||
734 | |||
735 | void resume_console(void) | ||
736 | { | ||
737 | console_suspended = 0; | ||
738 | release_console_sem(); | ||
739 | } | ||
740 | |||
741 | /** | ||
701 | * acquire_console_sem - lock the console system for exclusive use. | 742 | * acquire_console_sem - lock the console system for exclusive use. |
702 | * | 743 | * |
703 | * Acquires a semaphore which guarantees that the caller has | 744 | * Acquires a semaphore which guarantees that the caller has |
@@ -708,6 +749,10 @@ int __init add_preferred_console(char *name, int idx, char *options) | |||
708 | void acquire_console_sem(void) | 749 | void acquire_console_sem(void) |
709 | { | 750 | { |
710 | BUG_ON(in_interrupt()); | 751 | BUG_ON(in_interrupt()); |
752 | if (console_suspended) { | ||
753 | down(&secondary_console_sem); | ||
754 | return; | ||
755 | } | ||
711 | down(&console_sem); | 756 | down(&console_sem); |
712 | console_locked = 1; | 757 | console_locked = 1; |
713 | console_may_schedule = 1; | 758 | console_may_schedule = 1; |
@@ -728,7 +773,7 @@ int is_console_locked(void) | |||
728 | { | 773 | { |
729 | return console_locked; | 774 | return console_locked; |
730 | } | 775 | } |
731 | EXPORT_SYMBOL(is_console_locked); | 776 | EXPORT_UNUSED_SYMBOL(is_console_locked); /* June 2006 */ |
732 | 777 | ||
733 | /** | 778 | /** |
734 | * release_console_sem - unlock the console system | 779 | * release_console_sem - unlock the console system |
@@ -750,6 +795,10 @@ void release_console_sem(void) | |||
750 | unsigned long _con_start, _log_end; | 795 | unsigned long _con_start, _log_end; |
751 | unsigned long wake_klogd = 0; | 796 | unsigned long wake_klogd = 0; |
752 | 797 | ||
798 | if (console_suspended) { | ||
799 | up(&secondary_console_sem); | ||
800 | return; | ||
801 | } | ||
753 | for ( ; ; ) { | 802 | for ( ; ; ) { |
754 | spin_lock_irqsave(&logbuf_lock, flags); | 803 | spin_lock_irqsave(&logbuf_lock, flags); |
755 | wake_klogd |= log_start - log_end; | 804 | wake_klogd |= log_start - log_end; |
@@ -766,8 +815,15 @@ void release_console_sem(void) | |||
766 | console_may_schedule = 0; | 815 | console_may_schedule = 0; |
767 | up(&console_sem); | 816 | up(&console_sem); |
768 | spin_unlock_irqrestore(&logbuf_lock, flags); | 817 | spin_unlock_irqrestore(&logbuf_lock, flags); |
769 | if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait)) | 818 | if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait)) { |
770 | wake_up_interruptible(&log_wait); | 819 | /* |
820 | * If we printk from within the lock dependency code, | ||
821 | * from within the scheduler code, then do not lock | ||
822 | * up due to self-recursion: | ||
823 | */ | ||
824 | if (!lockdep_internal()) | ||
825 | wake_up_interruptible(&log_wait); | ||
826 | } | ||
771 | } | 827 | } |
772 | EXPORT_SYMBOL(release_console_sem); | 828 | EXPORT_SYMBOL(release_console_sem); |
773 | 829 | ||