diff options
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 62 |
1 files changed, 46 insertions, 16 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 89011bf8c106..58bbec684119 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -36,6 +36,13 @@ | |||
36 | 36 | ||
37 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
38 | 38 | ||
39 | /* | ||
40 | * Architectures can override it: | ||
41 | */ | ||
42 | void __attribute__((weak)) early_printk(const char *fmt, ...) | ||
43 | { | ||
44 | } | ||
45 | |||
39 | #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) | 46 | #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) |
40 | 47 | ||
41 | /* printk's without a loglevel use this.. */ | 48 | /* printk's without a loglevel use this.. */ |
@@ -573,11 +580,6 @@ static int __init printk_time_setup(char *str) | |||
573 | 580 | ||
574 | __setup("time", printk_time_setup); | 581 | __setup("time", printk_time_setup); |
575 | 582 | ||
576 | __attribute__((weak)) unsigned long long printk_clock(void) | ||
577 | { | ||
578 | return sched_clock(); | ||
579 | } | ||
580 | |||
581 | /* Check if we have any console registered that can be called early in boot. */ | 583 | /* Check if we have any console registered that can be called early in boot. */ |
582 | static int have_callable_console(void) | 584 | static int have_callable_console(void) |
583 | { | 585 | { |
@@ -628,30 +630,57 @@ asmlinkage int printk(const char *fmt, ...) | |||
628 | /* cpu currently holding logbuf_lock */ | 630 | /* cpu currently holding logbuf_lock */ |
629 | static volatile unsigned int printk_cpu = UINT_MAX; | 631 | static volatile unsigned int printk_cpu = UINT_MAX; |
630 | 632 | ||
633 | const char printk_recursion_bug_msg [] = | ||
634 | KERN_CRIT "BUG: recent printk recursion!\n"; | ||
635 | static int printk_recursion_bug; | ||
636 | |||
631 | asmlinkage int vprintk(const char *fmt, va_list args) | 637 | asmlinkage int vprintk(const char *fmt, va_list args) |
632 | { | 638 | { |
639 | static int log_level_unknown = 1; | ||
640 | static char printk_buf[1024]; | ||
641 | |||
633 | unsigned long flags; | 642 | unsigned long flags; |
634 | int printed_len; | 643 | int printed_len = 0; |
644 | int this_cpu; | ||
635 | char *p; | 645 | char *p; |
636 | static char printk_buf[1024]; | ||
637 | static int log_level_unknown = 1; | ||
638 | 646 | ||
639 | boot_delay_msec(); | 647 | boot_delay_msec(); |
640 | 648 | ||
641 | preempt_disable(); | 649 | preempt_disable(); |
642 | if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id()) | ||
643 | /* If a crash is occurring during printk() on this CPU, | ||
644 | * make sure we can't deadlock */ | ||
645 | zap_locks(); | ||
646 | |||
647 | /* This stops the holder of console_sem just where we want him */ | 650 | /* This stops the holder of console_sem just where we want him */ |
648 | raw_local_irq_save(flags); | 651 | raw_local_irq_save(flags); |
652 | this_cpu = smp_processor_id(); | ||
653 | |||
654 | /* | ||
655 | * Ouch, printk recursed into itself! | ||
656 | */ | ||
657 | if (unlikely(printk_cpu == this_cpu)) { | ||
658 | /* | ||
659 | * If a crash is occurring during printk() on this CPU, | ||
660 | * then try to get the crash message out but make sure | ||
661 | * we can't deadlock. Otherwise just return to avoid the | ||
662 | * recursion and return - but flag the recursion so that | ||
663 | * it can be printed at the next appropriate moment: | ||
664 | */ | ||
665 | if (!oops_in_progress) { | ||
666 | printk_recursion_bug = 1; | ||
667 | goto out_restore_irqs; | ||
668 | } | ||
669 | zap_locks(); | ||
670 | } | ||
671 | |||
649 | lockdep_off(); | 672 | lockdep_off(); |
650 | spin_lock(&logbuf_lock); | 673 | spin_lock(&logbuf_lock); |
651 | printk_cpu = smp_processor_id(); | 674 | printk_cpu = this_cpu; |
652 | 675 | ||
676 | if (printk_recursion_bug) { | ||
677 | printk_recursion_bug = 0; | ||
678 | strcpy(printk_buf, printk_recursion_bug_msg); | ||
679 | printed_len = sizeof(printk_recursion_bug_msg); | ||
680 | } | ||
653 | /* Emit the output into the temporary buffer */ | 681 | /* Emit the output into the temporary buffer */ |
654 | printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args); | 682 | printed_len += vscnprintf(printk_buf + printed_len, |
683 | sizeof(printk_buf), fmt, args); | ||
655 | 684 | ||
656 | /* | 685 | /* |
657 | * Copy the output into log_buf. If the caller didn't provide | 686 | * Copy the output into log_buf. If the caller didn't provide |
@@ -680,7 +709,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
680 | loglev_char = default_message_loglevel | 709 | loglev_char = default_message_loglevel |
681 | + '0'; | 710 | + '0'; |
682 | } | 711 | } |
683 | t = printk_clock(); | 712 | t = cpu_clock(printk_cpu); |
684 | nanosec_rem = do_div(t, 1000000000); | 713 | nanosec_rem = do_div(t, 1000000000); |
685 | tlen = sprintf(tbuf, | 714 | tlen = sprintf(tbuf, |
686 | "<%c>[%5lu.%06lu] ", | 715 | "<%c>[%5lu.%06lu] ", |
@@ -744,6 +773,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
744 | printk_cpu = UINT_MAX; | 773 | printk_cpu = UINT_MAX; |
745 | spin_unlock(&logbuf_lock); | 774 | spin_unlock(&logbuf_lock); |
746 | lockdep_on(); | 775 | lockdep_on(); |
776 | out_restore_irqs: | ||
747 | raw_local_irq_restore(flags); | 777 | raw_local_irq_restore(flags); |
748 | } | 778 | } |
749 | 779 | ||