diff options
Diffstat (limited to 'kernel/printk.c')
| -rw-r--r-- | kernel/printk.c | 87 |
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 | ||
| 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 |
| @@ -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 |
| 438 | static int printk_time = 0; | 440 | static int printk_time = 0; |
| 439 | #endif | 441 | #endif |
| 442 | module_param(printk_time, int, S_IRUGO | S_IWUSR); | ||
| 440 | 443 | ||
| 441 | static int __init printk_time_setup(char *str) | 444 | static 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. */ | ||
| 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 | |||
| 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 | } |
| 599 | out: | 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 | */ |
| 706 | void suspend_console(void) | 730 | void 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 | } |
| 753 | EXPORT_SYMBOL(is_console_locked); | 779 | EXPORT_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 | } |
| 798 | EXPORT_SYMBOL(release_console_sem); | 833 | EXPORT_SYMBOL(release_console_sem); |
| 799 | 834 | ||
