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 | |
| 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')
| -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; |
