diff options
Diffstat (limited to 'kernel/printk.c')
| -rw-r--r-- | kernel/printk.c | 131 |
1 files changed, 54 insertions, 77 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index e2129e83fd75..a7f7559c5f6c 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 | static 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); |
| @@ -950,7 +933,7 @@ void suspend_console(void) | |||
| 950 | { | 933 | { |
| 951 | if (!console_suspend_enabled) | 934 | if (!console_suspend_enabled) |
| 952 | return; | 935 | return; |
| 953 | printk("Suspending console(s)\n"); | 936 | printk("Suspending console(s) (use no_console_suspend to debug)\n"); |
| 954 | acquire_console_sem(); | 937 | acquire_console_sem(); |
| 955 | console_suspended = 1; | 938 | console_suspended = 1; |
| 956 | } | 939 | } |
| @@ -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 | ||
| @@ -1320,6 +1308,8 @@ void tty_write_message(struct tty_struct *tty, char *msg) | |||
| 1320 | } | 1308 | } |
| 1321 | 1309 | ||
| 1322 | #if defined CONFIG_PRINTK | 1310 | #if defined CONFIG_PRINTK |
| 1311 | |||
| 1312 | DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10); | ||
| 1323 | /* | 1313 | /* |
| 1324 | * printk rate limiting, lifted from the networking subsystem. | 1314 | * printk rate limiting, lifted from the networking subsystem. |
| 1325 | * | 1315 | * |
| @@ -1327,22 +1317,9 @@ void tty_write_message(struct tty_struct *tty, char *msg) | |||
| 1327 | * every printk_ratelimit_jiffies to make a denial-of-service | 1317 | * every printk_ratelimit_jiffies to make a denial-of-service |
| 1328 | * attack impossible. | 1318 | * attack impossible. |
| 1329 | */ | 1319 | */ |
| 1330 | int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst) | ||
| 1331 | { | ||
| 1332 | return __ratelimit(ratelimit_jiffies, ratelimit_burst); | ||
| 1333 | } | ||
| 1334 | EXPORT_SYMBOL(__printk_ratelimit); | ||
| 1335 | |||
| 1336 | /* minimum time in jiffies between messages */ | ||
| 1337 | int printk_ratelimit_jiffies = 5 * HZ; | ||
| 1338 | |||
| 1339 | /* number of messages we send before ratelimiting */ | ||
| 1340 | int printk_ratelimit_burst = 10; | ||
| 1341 | |||
| 1342 | int printk_ratelimit(void) | 1320 | int printk_ratelimit(void) |
| 1343 | { | 1321 | { |
| 1344 | return __printk_ratelimit(printk_ratelimit_jiffies, | 1322 | return __ratelimit(&printk_ratelimit_state); |
| 1345 | printk_ratelimit_burst); | ||
| 1346 | } | 1323 | } |
| 1347 | EXPORT_SYMBOL(printk_ratelimit); | 1324 | EXPORT_SYMBOL(printk_ratelimit); |
| 1348 | 1325 | ||
