diff options
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 112 |
1 files changed, 50 insertions, 62 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 8fb01c32aa3b..07ad9e7f7a66 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -38,7 +38,7 @@ | |||
38 | /* | 38 | /* |
39 | * Architectures can override it: | 39 | * Architectures can override it: |
40 | */ | 40 | */ |
41 | void __attribute__((weak)) early_printk(const char *fmt, ...) | 41 | void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...) |
42 | { | 42 | { |
43 | } | 43 | } |
44 | 44 | ||
@@ -75,6 +75,8 @@ EXPORT_SYMBOL(oops_in_progress); | |||
75 | static DECLARE_MUTEX(console_sem); | 75 | static DECLARE_MUTEX(console_sem); |
76 | static DECLARE_MUTEX(secondary_console_sem); | 76 | static DECLARE_MUTEX(secondary_console_sem); |
77 | struct console *console_drivers; | 77 | struct console *console_drivers; |
78 | EXPORT_SYMBOL_GPL(console_drivers); | ||
79 | |||
78 | /* | 80 | /* |
79 | * This is used for debugging the mess that is the VT code by | 81 | * This is used for debugging the mess that is the VT code by |
80 | * keeping track if we have the console semaphore held. It's | 82 | * keeping track if we have the console semaphore held. It's |
@@ -121,6 +123,8 @@ struct console_cmdline | |||
121 | static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; | 123 | static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; |
122 | static int selected_console = -1; | 124 | static int selected_console = -1; |
123 | static int preferred_console = -1; | 125 | static int preferred_console = -1; |
126 | int console_set_on_cmdline; | ||
127 | EXPORT_SYMBOL(console_set_on_cmdline); | ||
124 | 128 | ||
125 | /* Flag: console code may call schedule() */ | 129 | /* Flag: console code may call schedule() */ |
126 | static int console_may_schedule; | 130 | static int console_may_schedule; |
@@ -231,7 +235,7 @@ static inline void boot_delay_msec(void) | |||
231 | /* | 235 | /* |
232 | * Return the number of unread characters in the log buffer. | 236 | * Return the number of unread characters in the log buffer. |
233 | */ | 237 | */ |
234 | int log_buf_get_len(void) | 238 | static int log_buf_get_len(void) |
235 | { | 239 | { |
236 | return logged_chars; | 240 | return logged_chars; |
237 | } | 241 | } |
@@ -268,19 +272,6 @@ int log_buf_copy(char *dest, int idx, int len) | |||
268 | } | 272 | } |
269 | 273 | ||
270 | /* | 274 | /* |
271 | * Extract a single character from the log buffer. | ||
272 | */ | ||
273 | int log_buf_read(int idx) | ||
274 | { | ||
275 | char ret; | ||
276 | |||
277 | if (log_buf_copy(&ret, idx, 1) == 1) | ||
278 | return ret; | ||
279 | else | ||
280 | return -1; | ||
281 | } | ||
282 | |||
283 | /* | ||
284 | * Commands to do_syslog: | 275 | * Commands to do_syslog: |
285 | * | 276 | * |
286 | * 0 -- Close the log. Currently a NOP. | 277 | * 0 -- Close the log. Currently a NOP. |
@@ -665,18 +656,17 @@ static int acquire_console_semaphore_for_printk(unsigned int cpu) | |||
665 | spin_unlock(&logbuf_lock); | 656 | spin_unlock(&logbuf_lock); |
666 | return retval; | 657 | return retval; |
667 | } | 658 | } |
668 | 659 | static const char recursion_bug_msg [] = | |
669 | const char printk_recursion_bug_msg [] = | 660 | KERN_CRIT "BUG: recent printk recursion!\n"; |
670 | KERN_CRIT "BUG: recent printk recursion!\n"; | 661 | static int recursion_bug; |
671 | static int printk_recursion_bug; | 662 | static int new_text_line = 1; |
663 | static char printk_buf[1024]; | ||
672 | 664 | ||
673 | asmlinkage int vprintk(const char *fmt, va_list args) | 665 | asmlinkage int vprintk(const char *fmt, va_list args) |
674 | { | 666 | { |
675 | static int log_level_unknown = 1; | ||
676 | static char printk_buf[1024]; | ||
677 | |||
678 | unsigned long flags; | ||
679 | int printed_len = 0; | 667 | int printed_len = 0; |
668 | int current_log_level = default_message_loglevel; | ||
669 | unsigned long flags; | ||
680 | int this_cpu; | 670 | int this_cpu; |
681 | char *p; | 671 | char *p; |
682 | 672 | ||
@@ -699,7 +689,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
699 | * it can be printed at the next appropriate moment: | 689 | * it can be printed at the next appropriate moment: |
700 | */ | 690 | */ |
701 | if (!oops_in_progress) { | 691 | if (!oops_in_progress) { |
702 | printk_recursion_bug = 1; | 692 | recursion_bug = 1; |
703 | goto out_restore_irqs; | 693 | goto out_restore_irqs; |
704 | } | 694 | } |
705 | zap_locks(); | 695 | zap_locks(); |
@@ -709,70 +699,62 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
709 | spin_lock(&logbuf_lock); | 699 | spin_lock(&logbuf_lock); |
710 | printk_cpu = this_cpu; | 700 | printk_cpu = this_cpu; |
711 | 701 | ||
712 | if (printk_recursion_bug) { | 702 | if (recursion_bug) { |
713 | printk_recursion_bug = 0; | 703 | recursion_bug = 0; |
714 | strcpy(printk_buf, printk_recursion_bug_msg); | 704 | strcpy(printk_buf, recursion_bug_msg); |
715 | printed_len = sizeof(printk_recursion_bug_msg); | 705 | printed_len = sizeof(recursion_bug_msg); |
716 | } | 706 | } |
717 | /* Emit the output into the temporary buffer */ | 707 | /* Emit the output into the temporary buffer */ |
718 | printed_len += vscnprintf(printk_buf + printed_len, | 708 | printed_len += vscnprintf(printk_buf + printed_len, |
719 | sizeof(printk_buf) - printed_len, fmt, args); | 709 | sizeof(printk_buf) - printed_len, fmt, args); |
720 | 710 | ||
711 | |||
721 | /* | 712 | /* |
722 | * Copy the output into log_buf. If the caller didn't provide | 713 | * Copy the output into log_buf. If the caller didn't provide |
723 | * appropriate log level tags, we insert them here | 714 | * appropriate log level tags, we insert them here |
724 | */ | 715 | */ |
725 | for (p = printk_buf; *p; p++) { | 716 | for (p = printk_buf; *p; p++) { |
726 | if (log_level_unknown) { | 717 | if (new_text_line) { |
727 | /* log_level_unknown signals the start of a new line */ | 718 | /* If a token, set current_log_level and skip over */ |
719 | if (p[0] == '<' && p[1] >= '0' && p[1] <= '7' && | ||
720 | p[2] == '>') { | ||
721 | current_log_level = p[1] - '0'; | ||
722 | p += 3; | ||
723 | printed_len -= 3; | ||
724 | } | ||
725 | |||
726 | /* Always output the token */ | ||
727 | emit_log_char('<'); | ||
728 | emit_log_char(current_log_level + '0'); | ||
729 | emit_log_char('>'); | ||
730 | printed_len += 3; | ||
731 | new_text_line = 0; | ||
732 | |||
728 | if (printk_time) { | 733 | if (printk_time) { |
729 | int loglev_char; | 734 | /* Follow the token with the time */ |
730 | char tbuf[50], *tp; | 735 | char tbuf[50], *tp; |
731 | unsigned tlen; | 736 | unsigned tlen; |
732 | unsigned long long t; | 737 | unsigned long long t; |
733 | unsigned long nanosec_rem; | 738 | unsigned long nanosec_rem; |
734 | 739 | ||
735 | /* | ||
736 | * force the log level token to be | ||
737 | * before the time output. | ||
738 | */ | ||
739 | if (p[0] == '<' && p[1] >='0' && | ||
740 | p[1] <= '7' && p[2] == '>') { | ||
741 | loglev_char = p[1]; | ||
742 | p += 3; | ||
743 | printed_len -= 3; | ||
744 | } else { | ||
745 | loglev_char = default_message_loglevel | ||
746 | + '0'; | ||
747 | } | ||
748 | t = cpu_clock(printk_cpu); | 740 | t = cpu_clock(printk_cpu); |
749 | nanosec_rem = do_div(t, 1000000000); | 741 | nanosec_rem = do_div(t, 1000000000); |
750 | tlen = sprintf(tbuf, | 742 | tlen = sprintf(tbuf, "[%5lu.%06lu] ", |
751 | "<%c>[%5lu.%06lu] ", | 743 | (unsigned long) t, |
752 | loglev_char, | 744 | nanosec_rem / 1000); |
753 | (unsigned long)t, | ||
754 | nanosec_rem/1000); | ||
755 | 745 | ||
756 | for (tp = tbuf; tp < tbuf + tlen; tp++) | 746 | for (tp = tbuf; tp < tbuf + tlen; tp++) |
757 | emit_log_char(*tp); | 747 | emit_log_char(*tp); |
758 | printed_len += tlen; | 748 | printed_len += tlen; |
759 | } else { | ||
760 | if (p[0] != '<' || p[1] < '0' || | ||
761 | p[1] > '7' || p[2] != '>') { | ||
762 | emit_log_char('<'); | ||
763 | emit_log_char(default_message_loglevel | ||
764 | + '0'); | ||
765 | emit_log_char('>'); | ||
766 | printed_len += 3; | ||
767 | } | ||
768 | } | 749 | } |
769 | log_level_unknown = 0; | 750 | |
770 | if (!*p) | 751 | if (!*p) |
771 | break; | 752 | break; |
772 | } | 753 | } |
754 | |||
773 | emit_log_char(*p); | 755 | emit_log_char(*p); |
774 | if (*p == '\n') | 756 | if (*p == '\n') |
775 | log_level_unknown = 1; | 757 | new_text_line = 1; |
776 | } | 758 | } |
777 | 759 | ||
778 | /* | 760 | /* |
@@ -890,6 +872,7 @@ static int __init console_setup(char *str) | |||
890 | *s = 0; | 872 | *s = 0; |
891 | 873 | ||
892 | __add_preferred_console(buf, idx, options, brl_options); | 874 | __add_preferred_console(buf, idx, options, brl_options); |
875 | console_set_on_cmdline = 1; | ||
893 | return 1; | 876 | return 1; |
894 | } | 877 | } |
895 | __setup("console=", console_setup); | 878 | __setup("console=", console_setup); |
@@ -1041,7 +1024,9 @@ void release_console_sem(void) | |||
1041 | _log_end = log_end; | 1024 | _log_end = log_end; |
1042 | con_start = log_end; /* Flush */ | 1025 | con_start = log_end; /* Flush */ |
1043 | spin_unlock(&logbuf_lock); | 1026 | spin_unlock(&logbuf_lock); |
1027 | stop_critical_timings(); /* don't trace print latency */ | ||
1044 | call_console_drivers(_con_start, _log_end); | 1028 | call_console_drivers(_con_start, _log_end); |
1029 | start_critical_timings(); | ||
1045 | local_irq_restore(flags); | 1030 | local_irq_restore(flags); |
1046 | } | 1031 | } |
1047 | console_locked = 0; | 1032 | console_locked = 0; |
@@ -1172,8 +1157,11 @@ void register_console(struct console *console) | |||
1172 | console->index = 0; | 1157 | console->index = 0; |
1173 | if (console->setup == NULL || | 1158 | if (console->setup == NULL || |
1174 | console->setup(console, NULL) == 0) { | 1159 | console->setup(console, NULL) == 0) { |
1175 | console->flags |= CON_ENABLED | CON_CONSDEV; | 1160 | console->flags |= CON_ENABLED; |
1176 | preferred_console = 0; | 1161 | if (console->device) { |
1162 | console->flags |= CON_CONSDEV; | ||
1163 | preferred_console = 0; | ||
1164 | } | ||
1177 | } | 1165 | } |
1178 | } | 1166 | } |
1179 | 1167 | ||