diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 18:05:40 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 18:05:40 -0400 |
commit | a5e6b135bdff649e4330f98e2e80dbb1984f7e77 (patch) | |
tree | 475bfb1163c59d1370fd77415255afba768f9520 /kernel/printk.c | |
parent | 971f115a50afbe409825c9f3399d5a3b9aca4381 (diff) | |
parent | 9d90c8d9cde929cbc575098e825d7c29d9f45054 (diff) |
Merge branch 'driver-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6
* 'driver-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6: (50 commits)
printk: do not mangle valid userspace syslog prefixes
efivars: Add Documentation
efivars: Expose efivars functionality to external drivers.
efivars: Parameterize operations.
efivars: Split out variable registration
efivars: parameterize efivars
efivars: Make efivars bin_attributes dynamic
efivars: move efivars globals into struct efivars
drivers:misc: ti-st: fix debugging code
kref: Fix typo in kref documentation
UIO: add PRUSS UIO driver support
Fix spelling mistakes in Documentation/zh_CN/SubmittingPatches
firmware: Fix unaligned memory accesses in dmi-sysfs
firmware: Add documentation for /sys/firmware/dmi
firmware: Expose DMI type 15 System Event Log
firmware: Break out system_event_log in dmi-sysfs
firmware: Basic dmi-sysfs support
firmware: Add DMI entry types to the headers
Driver core: convert platform_{get,set}_drvdata to static inline functions
Translate linux-2.6/Documentation/magic-number.txt into Chinese
...
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 138 |
1 files changed, 104 insertions, 34 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 36231525e22f..33284adb2189 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -515,6 +515,71 @@ static void _call_console_drivers(unsigned start, | |||
515 | } | 515 | } |
516 | 516 | ||
517 | /* | 517 | /* |
518 | * Parse the syslog header <[0-9]*>. The decimal value represents 32bit, the | ||
519 | * lower 3 bit are the log level, the rest are the log facility. In case | ||
520 | * userspace passes usual userspace syslog messages to /dev/kmsg or | ||
521 | * /dev/ttyprintk, the log prefix might contain the facility. Printk needs | ||
522 | * to extract the correct log level for in-kernel processing, and not mangle | ||
523 | * the original value. | ||
524 | * | ||
525 | * If a prefix is found, the length of the prefix is returned. If 'level' is | ||
526 | * passed, it will be filled in with the log level without a possible facility | ||
527 | * value. If 'special' is passed, the special printk prefix chars are accepted | ||
528 | * and returned. If no valid header is found, 0 is returned and the passed | ||
529 | * variables are not touched. | ||
530 | */ | ||
531 | static size_t log_prefix(const char *p, unsigned int *level, char *special) | ||
532 | { | ||
533 | unsigned int lev = 0; | ||
534 | char sp = '\0'; | ||
535 | size_t len; | ||
536 | |||
537 | if (p[0] != '<' || !p[1]) | ||
538 | return 0; | ||
539 | if (p[2] == '>') { | ||
540 | /* usual single digit level number or special char */ | ||
541 | switch (p[1]) { | ||
542 | case '0' ... '7': | ||
543 | lev = p[1] - '0'; | ||
544 | break; | ||
545 | case 'c': /* KERN_CONT */ | ||
546 | case 'd': /* KERN_DEFAULT */ | ||
547 | sp = p[1]; | ||
548 | break; | ||
549 | default: | ||
550 | return 0; | ||
551 | } | ||
552 | len = 3; | ||
553 | } else { | ||
554 | /* multi digit including the level and facility number */ | ||
555 | char *endp = NULL; | ||
556 | |||
557 | if (p[1] < '0' && p[1] > '9') | ||
558 | return 0; | ||
559 | |||
560 | lev = (simple_strtoul(&p[1], &endp, 10) & 7); | ||
561 | if (endp == NULL || endp[0] != '>') | ||
562 | return 0; | ||
563 | len = (endp + 1) - p; | ||
564 | } | ||
565 | |||
566 | /* do not accept special char if not asked for */ | ||
567 | if (sp && !special) | ||
568 | return 0; | ||
569 | |||
570 | if (special) { | ||
571 | *special = sp; | ||
572 | /* return special char, do not touch level */ | ||
573 | if (sp) | ||
574 | return len; | ||
575 | } | ||
576 | |||
577 | if (level) | ||
578 | *level = lev; | ||
579 | return len; | ||
580 | } | ||
581 | |||
582 | /* | ||
518 | * Call the console drivers, asking them to write out | 583 | * Call the console drivers, asking them to write out |
519 | * log_buf[start] to log_buf[end - 1]. | 584 | * log_buf[start] to log_buf[end - 1]. |
520 | * The console_lock must be held. | 585 | * The console_lock must be held. |
@@ -529,13 +594,9 @@ static void call_console_drivers(unsigned start, unsigned end) | |||
529 | cur_index = start; | 594 | cur_index = start; |
530 | start_print = start; | 595 | start_print = start; |
531 | while (cur_index != end) { | 596 | while (cur_index != end) { |
532 | if (msg_level < 0 && ((end - cur_index) > 2) && | 597 | if (msg_level < 0 && ((end - cur_index) > 2)) { |
533 | LOG_BUF(cur_index + 0) == '<' && | 598 | /* strip log prefix */ |
534 | LOG_BUF(cur_index + 1) >= '0' && | 599 | 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; | 600 | start_print = cur_index; |
540 | } | 601 | } |
541 | while (cur_index != end) { | 602 | while (cur_index != end) { |
@@ -733,6 +794,8 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
733 | unsigned long flags; | 794 | unsigned long flags; |
734 | int this_cpu; | 795 | int this_cpu; |
735 | char *p; | 796 | char *p; |
797 | size_t plen; | ||
798 | char special; | ||
736 | 799 | ||
737 | boot_delay_msec(); | 800 | boot_delay_msec(); |
738 | printk_delay(); | 801 | printk_delay(); |
@@ -773,45 +836,52 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
773 | printed_len += vscnprintf(printk_buf + printed_len, | 836 | printed_len += vscnprintf(printk_buf + printed_len, |
774 | sizeof(printk_buf) - printed_len, fmt, args); | 837 | sizeof(printk_buf) - printed_len, fmt, args); |
775 | 838 | ||
776 | |||
777 | p = printk_buf; | 839 | p = printk_buf; |
778 | 840 | ||
779 | /* Do we have a loglevel in the string? */ | 841 | /* Read log level and handle special printk prefix */ |
780 | if (p[0] == '<') { | 842 | plen = log_prefix(p, ¤t_log_level, &special); |
781 | unsigned char c = p[1]; | 843 | if (plen) { |
782 | if (c && p[2] == '>') { | 844 | p += plen; |
783 | switch (c) { | 845 | |
784 | case '0' ... '7': /* loglevel */ | 846 | switch (special) { |
785 | current_log_level = c - '0'; | 847 | case 'c': /* Strip <c> KERN_CONT, continue line */ |
786 | /* Fallthrough - make sure we're on a new line */ | 848 | plen = 0; |
787 | case 'd': /* KERN_DEFAULT */ | 849 | break; |
788 | if (!new_text_line) { | 850 | case 'd': /* Strip <d> KERN_DEFAULT, start new line */ |
789 | emit_log_char('\n'); | 851 | plen = 0; |
790 | new_text_line = 1; | 852 | default: |
791 | } | 853 | if (!new_text_line) { |
792 | /* Fallthrough - skip the loglevel */ | 854 | emit_log_char('\n'); |
793 | case 'c': /* KERN_CONT */ | 855 | new_text_line = 1; |
794 | p += 3; | ||
795 | break; | ||
796 | } | 856 | } |
797 | } | 857 | } |
798 | } | 858 | } |
799 | 859 | ||
800 | /* | 860 | /* |
801 | * Copy the output into log_buf. If the caller didn't provide | 861 | * Copy the output into log_buf. If the caller didn't provide |
802 | * appropriate log level tags, we insert them here | 862 | * the appropriate log prefix, we insert them here |
803 | */ | 863 | */ |
804 | for ( ; *p; p++) { | 864 | for (; *p; p++) { |
805 | if (new_text_line) { | 865 | 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; | 866 | new_text_line = 0; |
812 | 867 | ||
868 | if (plen) { | ||
869 | /* Copy original log prefix */ | ||
870 | int i; | ||
871 | |||
872 | for (i = 0; i < plen; i++) | ||
873 | emit_log_char(printk_buf[i]); | ||
874 | printed_len += plen; | ||
875 | } else { | ||
876 | /* Add log prefix */ | ||
877 | emit_log_char('<'); | ||
878 | emit_log_char(current_log_level + '0'); | ||
879 | emit_log_char('>'); | ||
880 | printed_len += 3; | ||
881 | } | ||
882 | |||
813 | if (printk_time) { | 883 | if (printk_time) { |
814 | /* Follow the token with the time */ | 884 | /* Add the current time stamp */ |
815 | char tbuf[50], *tp; | 885 | char tbuf[50], *tp; |
816 | unsigned tlen; | 886 | unsigned tlen; |
817 | unsigned long long t; | 887 | unsigned long long t; |