diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2011-05-14 06:06:36 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2011-05-14 06:06:36 -0400 |
commit | a18f22a968de17b29f2310cdb7ba69163e65ec15 (patch) | |
tree | a7d56d88fad5e444d7661484109758a2f436129e /kernel/printk.c | |
parent | a1c57e0fec53defe745e64417eacdbd3618c3e66 (diff) | |
parent | 798778b8653f64b7b2162ac70eca10367cff6ce8 (diff) |
Merge branch 'consolidate-clksrc-i8253' of master.kernel.org:~rmk/linux-2.6-arm into timers/clocksource
Conflicts:
arch/ia64/kernel/cyclone.c
arch/mips/kernel/i8253.c
arch/x86/kernel/i8253.c
Reason: Resolve conflicts so further cleanups do not conflict further
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 174 |
1 files changed, 138 insertions, 36 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 36231525e22f..da8ca817eae3 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -53,7 +53,7 @@ void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...) | |||
53 | #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) | 53 | #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) |
54 | 54 | ||
55 | /* printk's without a loglevel use this.. */ | 55 | /* printk's without a loglevel use this.. */ |
56 | #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */ | 56 | #define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL |
57 | 57 | ||
58 | /* We show everything that is MORE important than this.. */ | 58 | /* We show everything that is MORE important than this.. */ |
59 | #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */ | 59 | #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */ |
@@ -113,6 +113,11 @@ static unsigned con_start; /* Index into log_buf: next char to be sent to consol | |||
113 | static unsigned log_end; /* Index into log_buf: most-recently-written-char + 1 */ | 113 | static unsigned log_end; /* Index into log_buf: most-recently-written-char + 1 */ |
114 | 114 | ||
115 | /* | 115 | /* |
116 | * If exclusive_console is non-NULL then only this console is to be printed to. | ||
117 | */ | ||
118 | static struct console *exclusive_console; | ||
119 | |||
120 | /* | ||
116 | * Array of consoles built from command line options (console=) | 121 | * Array of consoles built from command line options (console=) |
117 | */ | 122 | */ |
118 | struct console_cmdline | 123 | struct console_cmdline |
@@ -476,6 +481,8 @@ static void __call_console_drivers(unsigned start, unsigned end) | |||
476 | struct console *con; | 481 | struct console *con; |
477 | 482 | ||
478 | for_each_console(con) { | 483 | for_each_console(con) { |
484 | if (exclusive_console && con != exclusive_console) | ||
485 | continue; | ||
479 | if ((con->flags & CON_ENABLED) && con->write && | 486 | if ((con->flags & CON_ENABLED) && con->write && |
480 | (cpu_online(smp_processor_id()) || | 487 | (cpu_online(smp_processor_id()) || |
481 | (con->flags & CON_ANYTIME))) | 488 | (con->flags & CON_ANYTIME))) |
@@ -515,6 +522,71 @@ static void _call_console_drivers(unsigned start, | |||
515 | } | 522 | } |
516 | 523 | ||
517 | /* | 524 | /* |
525 | * Parse the syslog header <[0-9]*>. The decimal value represents 32bit, the | ||
526 | * lower 3 bit are the log level, the rest are the log facility. In case | ||
527 | * userspace passes usual userspace syslog messages to /dev/kmsg or | ||
528 | * /dev/ttyprintk, the log prefix might contain the facility. Printk needs | ||
529 | * to extract the correct log level for in-kernel processing, and not mangle | ||
530 | * the original value. | ||
531 | * | ||
532 | * If a prefix is found, the length of the prefix is returned. If 'level' is | ||
533 | * passed, it will be filled in with the log level without a possible facility | ||
534 | * value. If 'special' is passed, the special printk prefix chars are accepted | ||
535 | * and returned. If no valid header is found, 0 is returned and the passed | ||
536 | * variables are not touched. | ||
537 | */ | ||
538 | static size_t log_prefix(const char *p, unsigned int *level, char *special) | ||
539 | { | ||
540 | unsigned int lev = 0; | ||
541 | char sp = '\0'; | ||
542 | size_t len; | ||
543 | |||
544 | if (p[0] != '<' || !p[1]) | ||
545 | return 0; | ||
546 | if (p[2] == '>') { | ||
547 | /* usual single digit level number or special char */ | ||
548 | switch (p[1]) { | ||
549 | case '0' ... '7': | ||
550 | lev = p[1] - '0'; | ||
551 | break; | ||
552 | case 'c': /* KERN_CONT */ | ||
553 | case 'd': /* KERN_DEFAULT */ | ||
554 | sp = p[1]; | ||
555 | break; | ||
556 | default: | ||
557 | return 0; | ||
558 | } | ||
559 | len = 3; | ||
560 | } else { | ||
561 | /* multi digit including the level and facility number */ | ||
562 | char *endp = NULL; | ||
563 | |||
564 | if (p[1] < '0' && p[1] > '9') | ||
565 | return 0; | ||
566 | |||
567 | lev = (simple_strtoul(&p[1], &endp, 10) & 7); | ||
568 | if (endp == NULL || endp[0] != '>') | ||
569 | return 0; | ||
570 | len = (endp + 1) - p; | ||
571 | } | ||
572 | |||
573 | /* do not accept special char if not asked for */ | ||
574 | if (sp && !special) | ||
575 | return 0; | ||
576 | |||
577 | if (special) { | ||
578 | *special = sp; | ||
579 | /* return special char, do not touch level */ | ||
580 | if (sp) | ||
581 | return len; | ||
582 | } | ||
583 | |||
584 | if (level) | ||
585 | *level = lev; | ||
586 | return len; | ||
587 | } | ||
588 | |||
589 | /* | ||
518 | * Call the console drivers, asking them to write out | 590 | * Call the console drivers, asking them to write out |
519 | * log_buf[start] to log_buf[end - 1]. | 591 | * log_buf[start] to log_buf[end - 1]. |
520 | * The console_lock must be held. | 592 | * The console_lock must be held. |
@@ -529,13 +601,9 @@ static void call_console_drivers(unsigned start, unsigned end) | |||
529 | cur_index = start; | 601 | cur_index = start; |
530 | start_print = start; | 602 | start_print = start; |
531 | while (cur_index != end) { | 603 | while (cur_index != end) { |
532 | if (msg_level < 0 && ((end - cur_index) > 2) && | 604 | if (msg_level < 0 && ((end - cur_index) > 2)) { |
533 | LOG_BUF(cur_index + 0) == '<' && | 605 | /* strip log prefix */ |
534 | LOG_BUF(cur_index + 1) >= '0' && | 606 | cur_index += log_prefix(&LOG_BUF(cur_index), &msg_level, NULL); |
535 | LOG_BUF(cur_index + 1) <= '7' && | ||
536 | LOG_BUF(cur_index + 2) == '>') { | ||
537 | msg_level = LOG_BUF(cur_index + 1) - '0'; | ||
538 | cur_index += 3; | ||
539 | start_print = cur_index; | 607 | start_print = cur_index; |
540 | } | 608 | } |
541 | while (cur_index != end) { | 609 | while (cur_index != end) { |
@@ -733,6 +801,8 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
733 | unsigned long flags; | 801 | unsigned long flags; |
734 | int this_cpu; | 802 | int this_cpu; |
735 | char *p; | 803 | char *p; |
804 | size_t plen; | ||
805 | char special; | ||
736 | 806 | ||
737 | boot_delay_msec(); | 807 | boot_delay_msec(); |
738 | printk_delay(); | 808 | printk_delay(); |
@@ -773,45 +843,52 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
773 | printed_len += vscnprintf(printk_buf + printed_len, | 843 | printed_len += vscnprintf(printk_buf + printed_len, |
774 | sizeof(printk_buf) - printed_len, fmt, args); | 844 | sizeof(printk_buf) - printed_len, fmt, args); |
775 | 845 | ||
776 | |||
777 | p = printk_buf; | 846 | p = printk_buf; |
778 | 847 | ||
779 | /* Do we have a loglevel in the string? */ | 848 | /* Read log level and handle special printk prefix */ |
780 | if (p[0] == '<') { | 849 | plen = log_prefix(p, ¤t_log_level, &special); |
781 | unsigned char c = p[1]; | 850 | if (plen) { |
782 | if (c && p[2] == '>') { | 851 | p += plen; |
783 | switch (c) { | 852 | |
784 | case '0' ... '7': /* loglevel */ | 853 | switch (special) { |
785 | current_log_level = c - '0'; | 854 | case 'c': /* Strip <c> KERN_CONT, continue line */ |
786 | /* Fallthrough - make sure we're on a new line */ | 855 | plen = 0; |
787 | case 'd': /* KERN_DEFAULT */ | 856 | break; |
788 | if (!new_text_line) { | 857 | case 'd': /* Strip <d> KERN_DEFAULT, start new line */ |
789 | emit_log_char('\n'); | 858 | plen = 0; |
790 | new_text_line = 1; | 859 | default: |
791 | } | 860 | if (!new_text_line) { |
792 | /* Fallthrough - skip the loglevel */ | 861 | emit_log_char('\n'); |
793 | case 'c': /* KERN_CONT */ | 862 | new_text_line = 1; |
794 | p += 3; | ||
795 | break; | ||
796 | } | 863 | } |
797 | } | 864 | } |
798 | } | 865 | } |
799 | 866 | ||
800 | /* | 867 | /* |
801 | * Copy the output into log_buf. If the caller didn't provide | 868 | * Copy the output into log_buf. If the caller didn't provide |
802 | * appropriate log level tags, we insert them here | 869 | * the appropriate log prefix, we insert them here |
803 | */ | 870 | */ |
804 | for ( ; *p; p++) { | 871 | for (; *p; p++) { |
805 | if (new_text_line) { | 872 | if (new_text_line) { |
806 | /* Always output the token */ | ||
807 | emit_log_char('<'); | ||
808 | emit_log_char(current_log_level + '0'); | ||
809 | emit_log_char('>'); | ||
810 | printed_len += 3; | ||
811 | new_text_line = 0; | 873 | new_text_line = 0; |
812 | 874 | ||
875 | if (plen) { | ||
876 | /* Copy original log prefix */ | ||
877 | int i; | ||
878 | |||
879 | for (i = 0; i < plen; i++) | ||
880 | emit_log_char(printk_buf[i]); | ||
881 | printed_len += plen; | ||
882 | } else { | ||
883 | /* Add log prefix */ | ||
884 | emit_log_char('<'); | ||
885 | emit_log_char(current_log_level + '0'); | ||
886 | emit_log_char('>'); | ||
887 | printed_len += 3; | ||
888 | } | ||
889 | |||
813 | if (printk_time) { | 890 | if (printk_time) { |
814 | /* Follow the token with the time */ | 891 | /* Add the current time stamp */ |
815 | char tbuf[50], *tp; | 892 | char tbuf[50], *tp; |
816 | unsigned tlen; | 893 | unsigned tlen; |
817 | unsigned long long t; | 894 | unsigned long long t; |
@@ -1160,6 +1237,11 @@ void console_unlock(void) | |||
1160 | local_irq_restore(flags); | 1237 | local_irq_restore(flags); |
1161 | } | 1238 | } |
1162 | console_locked = 0; | 1239 | console_locked = 0; |
1240 | |||
1241 | /* Release the exclusive_console once it is used */ | ||
1242 | if (unlikely(exclusive_console)) | ||
1243 | exclusive_console = NULL; | ||
1244 | |||
1163 | up(&console_sem); | 1245 | up(&console_sem); |
1164 | spin_unlock_irqrestore(&logbuf_lock, flags); | 1246 | spin_unlock_irqrestore(&logbuf_lock, flags); |
1165 | if (wake_klogd) | 1247 | if (wake_klogd) |
@@ -1246,6 +1328,18 @@ void console_start(struct console *console) | |||
1246 | } | 1328 | } |
1247 | EXPORT_SYMBOL(console_start); | 1329 | EXPORT_SYMBOL(console_start); |
1248 | 1330 | ||
1331 | static int __read_mostly keep_bootcon; | ||
1332 | |||
1333 | static int __init keep_bootcon_setup(char *str) | ||
1334 | { | ||
1335 | keep_bootcon = 1; | ||
1336 | printk(KERN_INFO "debug: skip boot console de-registration.\n"); | ||
1337 | |||
1338 | return 0; | ||
1339 | } | ||
1340 | |||
1341 | early_param("keep_bootcon", keep_bootcon_setup); | ||
1342 | |||
1249 | /* | 1343 | /* |
1250 | * The console driver calls this routine during kernel initialization | 1344 | * The console driver calls this routine during kernel initialization |
1251 | * to register the console printing procedure with printk() and to | 1345 | * to register the console printing procedure with printk() and to |
@@ -1382,6 +1476,12 @@ void register_console(struct console *newcon) | |||
1382 | spin_lock_irqsave(&logbuf_lock, flags); | 1476 | spin_lock_irqsave(&logbuf_lock, flags); |
1383 | con_start = log_start; | 1477 | con_start = log_start; |
1384 | spin_unlock_irqrestore(&logbuf_lock, flags); | 1478 | spin_unlock_irqrestore(&logbuf_lock, flags); |
1479 | /* | ||
1480 | * We're about to replay the log buffer. Only do this to the | ||
1481 | * just-registered console to avoid excessive message spam to | ||
1482 | * the already-registered consoles. | ||
1483 | */ | ||
1484 | exclusive_console = newcon; | ||
1385 | } | 1485 | } |
1386 | console_unlock(); | 1486 | console_unlock(); |
1387 | console_sysfs_notify(); | 1487 | console_sysfs_notify(); |
@@ -1393,7 +1493,9 @@ void register_console(struct console *newcon) | |||
1393 | * users know there might be something in the kernel's log buffer that | 1493 | * users know there might be something in the kernel's log buffer that |
1394 | * went to the bootconsole (that they do not see on the real console) | 1494 | * went to the bootconsole (that they do not see on the real console) |
1395 | */ | 1495 | */ |
1396 | if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) { | 1496 | if (bcon && |
1497 | ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV) && | ||
1498 | !keep_bootcon) { | ||
1397 | /* we need to iterate through twice, to make sure we print | 1499 | /* we need to iterate through twice, to make sure we print |
1398 | * everything out, before we unregister the console(s) | 1500 | * everything out, before we unregister the console(s) |
1399 | */ | 1501 | */ |