diff options
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 328 |
1 files changed, 227 insertions, 101 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 53d9a9ec88e6..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 */ |
@@ -97,7 +97,7 @@ static int console_locked, console_suspended; | |||
97 | /* | 97 | /* |
98 | * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars | 98 | * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars |
99 | * It is also used in interesting ways to provide interlocking in | 99 | * It is also used in interesting ways to provide interlocking in |
100 | * release_console_sem(). | 100 | * console_unlock();. |
101 | */ | 101 | */ |
102 | static DEFINE_SPINLOCK(logbuf_lock); | 102 | static DEFINE_SPINLOCK(logbuf_lock); |
103 | 103 | ||
@@ -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 |
@@ -262,25 +267,47 @@ int dmesg_restrict = 1; | |||
262 | int dmesg_restrict; | 267 | int dmesg_restrict; |
263 | #endif | 268 | #endif |
264 | 269 | ||
270 | static int syslog_action_restricted(int type) | ||
271 | { | ||
272 | if (dmesg_restrict) | ||
273 | return 1; | ||
274 | /* Unless restricted, we allow "read all" and "get buffer size" for everybody */ | ||
275 | return type != SYSLOG_ACTION_READ_ALL && type != SYSLOG_ACTION_SIZE_BUFFER; | ||
276 | } | ||
277 | |||
278 | static int check_syslog_permissions(int type, bool from_file) | ||
279 | { | ||
280 | /* | ||
281 | * If this is from /proc/kmsg and we've already opened it, then we've | ||
282 | * already done the capabilities checks at open time. | ||
283 | */ | ||
284 | if (from_file && type != SYSLOG_ACTION_OPEN) | ||
285 | return 0; | ||
286 | |||
287 | if (syslog_action_restricted(type)) { | ||
288 | if (capable(CAP_SYSLOG)) | ||
289 | return 0; | ||
290 | /* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */ | ||
291 | if (capable(CAP_SYS_ADMIN)) { | ||
292 | WARN_ONCE(1, "Attempt to access syslog with CAP_SYS_ADMIN " | ||
293 | "but no CAP_SYSLOG (deprecated).\n"); | ||
294 | return 0; | ||
295 | } | ||
296 | return -EPERM; | ||
297 | } | ||
298 | return 0; | ||
299 | } | ||
300 | |||
265 | int do_syslog(int type, char __user *buf, int len, bool from_file) | 301 | int do_syslog(int type, char __user *buf, int len, bool from_file) |
266 | { | 302 | { |
267 | unsigned i, j, limit, count; | 303 | unsigned i, j, limit, count; |
268 | int do_clear = 0; | 304 | int do_clear = 0; |
269 | char c; | 305 | char c; |
270 | int error = 0; | 306 | int error; |
271 | 307 | ||
272 | /* | 308 | error = check_syslog_permissions(type, from_file); |
273 | * If this is from /proc/kmsg we only do the capabilities checks | 309 | if (error) |
274 | * at open time. | 310 | goto out; |
275 | */ | ||
276 | if (type == SYSLOG_ACTION_OPEN || !from_file) { | ||
277 | if (dmesg_restrict && !capable(CAP_SYSLOG)) | ||
278 | goto warn; /* switch to return -EPERM after 2.6.39 */ | ||
279 | if ((type != SYSLOG_ACTION_READ_ALL && | ||
280 | type != SYSLOG_ACTION_SIZE_BUFFER) && | ||
281 | !capable(CAP_SYSLOG)) | ||
282 | goto warn; /* switch to return -EPERM after 2.6.39 */ | ||
283 | } | ||
284 | 311 | ||
285 | error = security_syslog(type); | 312 | error = security_syslog(type); |
286 | if (error) | 313 | if (error) |
@@ -423,12 +450,6 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) | |||
423 | } | 450 | } |
424 | out: | 451 | out: |
425 | return error; | 452 | return error; |
426 | warn: | ||
427 | /* remove after 2.6.39 */ | ||
428 | if (capable(CAP_SYS_ADMIN)) | ||
429 | WARN_ONCE(1, "Attempt to access syslog with CAP_SYS_ADMIN " | ||
430 | "but no CAP_SYSLOG (deprecated and denied).\n"); | ||
431 | return -EPERM; | ||
432 | } | 453 | } |
433 | 454 | ||
434 | SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) | 455 | SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) |
@@ -460,6 +481,8 @@ static void __call_console_drivers(unsigned start, unsigned end) | |||
460 | struct console *con; | 481 | struct console *con; |
461 | 482 | ||
462 | for_each_console(con) { | 483 | for_each_console(con) { |
484 | if (exclusive_console && con != exclusive_console) | ||
485 | continue; | ||
463 | if ((con->flags & CON_ENABLED) && con->write && | 486 | if ((con->flags & CON_ENABLED) && con->write && |
464 | (cpu_online(smp_processor_id()) || | 487 | (cpu_online(smp_processor_id()) || |
465 | (con->flags & CON_ANYTIME))) | 488 | (con->flags & CON_ANYTIME))) |
@@ -499,9 +522,74 @@ static void _call_console_drivers(unsigned start, | |||
499 | } | 522 | } |
500 | 523 | ||
501 | /* | 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 | /* | ||
502 | * Call the console drivers, asking them to write out | 590 | * Call the console drivers, asking them to write out |
503 | * log_buf[start] to log_buf[end - 1]. | 591 | * log_buf[start] to log_buf[end - 1]. |
504 | * The console_sem must be held. | 592 | * The console_lock must be held. |
505 | */ | 593 | */ |
506 | static void call_console_drivers(unsigned start, unsigned end) | 594 | static void call_console_drivers(unsigned start, unsigned end) |
507 | { | 595 | { |
@@ -513,13 +601,9 @@ static void call_console_drivers(unsigned start, unsigned end) | |||
513 | cur_index = start; | 601 | cur_index = start; |
514 | start_print = start; | 602 | start_print = start; |
515 | while (cur_index != end) { | 603 | while (cur_index != end) { |
516 | if (msg_level < 0 && ((end - cur_index) > 2) && | 604 | if (msg_level < 0 && ((end - cur_index) > 2)) { |
517 | LOG_BUF(cur_index + 0) == '<' && | 605 | /* strip log prefix */ |
518 | LOG_BUF(cur_index + 1) >= '0' && | 606 | cur_index += log_prefix(&LOG_BUF(cur_index), &msg_level, NULL); |
519 | LOG_BUF(cur_index + 1) <= '7' && | ||
520 | LOG_BUF(cur_index + 2) == '>') { | ||
521 | msg_level = LOG_BUF(cur_index + 1) - '0'; | ||
522 | cur_index += 3; | ||
523 | start_print = cur_index; | 607 | start_print = cur_index; |
524 | } | 608 | } |
525 | while (cur_index != end) { | 609 | while (cur_index != end) { |
@@ -604,11 +688,11 @@ static int have_callable_console(void) | |||
604 | * | 688 | * |
605 | * This is printk(). It can be called from any context. We want it to work. | 689 | * This is printk(). It can be called from any context. We want it to work. |
606 | * | 690 | * |
607 | * We try to grab the console_sem. If we succeed, it's easy - we log the output and | 691 | * We try to grab the console_lock. If we succeed, it's easy - we log the output and |
608 | * call the console drivers. If we fail to get the semaphore we place the output | 692 | * call the console drivers. If we fail to get the semaphore we place the output |
609 | * into the log buffer and return. The current holder of the console_sem will | 693 | * into the log buffer and return. The current holder of the console_sem will |
610 | * notice the new output in release_console_sem() and will send it to the | 694 | * notice the new output in console_unlock(); and will send it to the |
611 | * consoles before releasing the semaphore. | 695 | * consoles before releasing the lock. |
612 | * | 696 | * |
613 | * One effect of this deferred printing is that code which calls printk() and | 697 | * One effect of this deferred printing is that code which calls printk() and |
614 | * then changes console_loglevel may break. This is because console_loglevel | 698 | * then changes console_loglevel may break. This is because console_loglevel |
@@ -659,19 +743,19 @@ static inline int can_use_console(unsigned int cpu) | |||
659 | /* | 743 | /* |
660 | * Try to get console ownership to actually show the kernel | 744 | * Try to get console ownership to actually show the kernel |
661 | * messages from a 'printk'. Return true (and with the | 745 | * messages from a 'printk'. Return true (and with the |
662 | * console_semaphore held, and 'console_locked' set) if it | 746 | * console_lock held, and 'console_locked' set) if it |
663 | * is successful, false otherwise. | 747 | * is successful, false otherwise. |
664 | * | 748 | * |
665 | * This gets called with the 'logbuf_lock' spinlock held and | 749 | * This gets called with the 'logbuf_lock' spinlock held and |
666 | * interrupts disabled. It should return with 'lockbuf_lock' | 750 | * interrupts disabled. It should return with 'lockbuf_lock' |
667 | * released but interrupts still disabled. | 751 | * released but interrupts still disabled. |
668 | */ | 752 | */ |
669 | static int acquire_console_semaphore_for_printk(unsigned int cpu) | 753 | static int console_trylock_for_printk(unsigned int cpu) |
670 | __releases(&logbuf_lock) | 754 | __releases(&logbuf_lock) |
671 | { | 755 | { |
672 | int retval = 0; | 756 | int retval = 0; |
673 | 757 | ||
674 | if (!try_acquire_console_sem()) { | 758 | if (console_trylock()) { |
675 | retval = 1; | 759 | retval = 1; |
676 | 760 | ||
677 | /* | 761 | /* |
@@ -717,6 +801,8 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
717 | unsigned long flags; | 801 | unsigned long flags; |
718 | int this_cpu; | 802 | int this_cpu; |
719 | char *p; | 803 | char *p; |
804 | size_t plen; | ||
805 | char special; | ||
720 | 806 | ||
721 | boot_delay_msec(); | 807 | boot_delay_msec(); |
722 | printk_delay(); | 808 | printk_delay(); |
@@ -757,45 +843,52 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
757 | printed_len += vscnprintf(printk_buf + printed_len, | 843 | printed_len += vscnprintf(printk_buf + printed_len, |
758 | sizeof(printk_buf) - printed_len, fmt, args); | 844 | sizeof(printk_buf) - printed_len, fmt, args); |
759 | 845 | ||
760 | |||
761 | p = printk_buf; | 846 | p = printk_buf; |
762 | 847 | ||
763 | /* Do we have a loglevel in the string? */ | 848 | /* Read log level and handle special printk prefix */ |
764 | if (p[0] == '<') { | 849 | plen = log_prefix(p, ¤t_log_level, &special); |
765 | unsigned char c = p[1]; | 850 | if (plen) { |
766 | if (c && p[2] == '>') { | 851 | p += plen; |
767 | switch (c) { | 852 | |
768 | case '0' ... '7': /* loglevel */ | 853 | switch (special) { |
769 | current_log_level = c - '0'; | 854 | case 'c': /* Strip <c> KERN_CONT, continue line */ |
770 | /* Fallthrough - make sure we're on a new line */ | 855 | plen = 0; |
771 | case 'd': /* KERN_DEFAULT */ | 856 | break; |
772 | if (!new_text_line) { | 857 | case 'd': /* Strip <d> KERN_DEFAULT, start new line */ |
773 | emit_log_char('\n'); | 858 | plen = 0; |
774 | new_text_line = 1; | 859 | default: |
775 | } | 860 | if (!new_text_line) { |
776 | /* Fallthrough - skip the loglevel */ | 861 | emit_log_char('\n'); |
777 | case 'c': /* KERN_CONT */ | 862 | new_text_line = 1; |
778 | p += 3; | ||
779 | break; | ||
780 | } | 863 | } |
781 | } | 864 | } |
782 | } | 865 | } |
783 | 866 | ||
784 | /* | 867 | /* |
785 | * 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 |
786 | * appropriate log level tags, we insert them here | 869 | * the appropriate log prefix, we insert them here |
787 | */ | 870 | */ |
788 | for ( ; *p; p++) { | 871 | for (; *p; p++) { |
789 | if (new_text_line) { | 872 | if (new_text_line) { |
790 | /* Always output the token */ | ||
791 | emit_log_char('<'); | ||
792 | emit_log_char(current_log_level + '0'); | ||
793 | emit_log_char('>'); | ||
794 | printed_len += 3; | ||
795 | new_text_line = 0; | 873 | new_text_line = 0; |
796 | 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 | |||
797 | if (printk_time) { | 890 | if (printk_time) { |
798 | /* Follow the token with the time */ | 891 | /* Add the current time stamp */ |
799 | char tbuf[50], *tp; | 892 | char tbuf[50], *tp; |
800 | unsigned tlen; | 893 | unsigned tlen; |
801 | unsigned long long t; | 894 | unsigned long long t; |
@@ -827,12 +920,12 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
827 | * actual magic (print out buffers, wake up klogd, | 920 | * actual magic (print out buffers, wake up klogd, |
828 | * etc). | 921 | * etc). |
829 | * | 922 | * |
830 | * The acquire_console_semaphore_for_printk() function | 923 | * The console_trylock_for_printk() function |
831 | * will release 'logbuf_lock' regardless of whether it | 924 | * will release 'logbuf_lock' regardless of whether it |
832 | * actually gets the semaphore or not. | 925 | * actually gets the semaphore or not. |
833 | */ | 926 | */ |
834 | if (acquire_console_semaphore_for_printk(this_cpu)) | 927 | if (console_trylock_for_printk(this_cpu)) |
835 | release_console_sem(); | 928 | console_unlock(); |
836 | 929 | ||
837 | lockdep_on(); | 930 | lockdep_on(); |
838 | out_restore_irqs: | 931 | out_restore_irqs: |
@@ -993,7 +1086,7 @@ void suspend_console(void) | |||
993 | if (!console_suspend_enabled) | 1086 | if (!console_suspend_enabled) |
994 | return; | 1087 | return; |
995 | printk("Suspending console(s) (use no_console_suspend to debug)\n"); | 1088 | printk("Suspending console(s) (use no_console_suspend to debug)\n"); |
996 | acquire_console_sem(); | 1089 | console_lock(); |
997 | console_suspended = 1; | 1090 | console_suspended = 1; |
998 | up(&console_sem); | 1091 | up(&console_sem); |
999 | } | 1092 | } |
@@ -1004,7 +1097,7 @@ void resume_console(void) | |||
1004 | return; | 1097 | return; |
1005 | down(&console_sem); | 1098 | down(&console_sem); |
1006 | console_suspended = 0; | 1099 | console_suspended = 0; |
1007 | release_console_sem(); | 1100 | console_unlock(); |
1008 | } | 1101 | } |
1009 | 1102 | ||
1010 | /** | 1103 | /** |
@@ -1027,21 +1120,21 @@ static int __cpuinit console_cpu_notify(struct notifier_block *self, | |||
1027 | case CPU_DYING: | 1120 | case CPU_DYING: |
1028 | case CPU_DOWN_FAILED: | 1121 | case CPU_DOWN_FAILED: |
1029 | case CPU_UP_CANCELED: | 1122 | case CPU_UP_CANCELED: |
1030 | acquire_console_sem(); | 1123 | console_lock(); |
1031 | release_console_sem(); | 1124 | console_unlock(); |
1032 | } | 1125 | } |
1033 | return NOTIFY_OK; | 1126 | return NOTIFY_OK; |
1034 | } | 1127 | } |
1035 | 1128 | ||
1036 | /** | 1129 | /** |
1037 | * acquire_console_sem - lock the console system for exclusive use. | 1130 | * console_lock - lock the console system for exclusive use. |
1038 | * | 1131 | * |
1039 | * Acquires a semaphore which guarantees that the caller has | 1132 | * Acquires a lock which guarantees that the caller has |
1040 | * exclusive access to the console system and the console_drivers list. | 1133 | * exclusive access to the console system and the console_drivers list. |
1041 | * | 1134 | * |
1042 | * Can sleep, returns nothing. | 1135 | * Can sleep, returns nothing. |
1043 | */ | 1136 | */ |
1044 | void acquire_console_sem(void) | 1137 | void console_lock(void) |
1045 | { | 1138 | { |
1046 | BUG_ON(in_interrupt()); | 1139 | BUG_ON(in_interrupt()); |
1047 | down(&console_sem); | 1140 | down(&console_sem); |
@@ -1050,21 +1143,29 @@ void acquire_console_sem(void) | |||
1050 | console_locked = 1; | 1143 | console_locked = 1; |
1051 | console_may_schedule = 1; | 1144 | console_may_schedule = 1; |
1052 | } | 1145 | } |
1053 | EXPORT_SYMBOL(acquire_console_sem); | 1146 | EXPORT_SYMBOL(console_lock); |
1054 | 1147 | ||
1055 | int try_acquire_console_sem(void) | 1148 | /** |
1149 | * console_trylock - try to lock the console system for exclusive use. | ||
1150 | * | ||
1151 | * Tried to acquire a lock which guarantees that the caller has | ||
1152 | * exclusive access to the console system and the console_drivers list. | ||
1153 | * | ||
1154 | * returns 1 on success, and 0 on failure to acquire the lock. | ||
1155 | */ | ||
1156 | int console_trylock(void) | ||
1056 | { | 1157 | { |
1057 | if (down_trylock(&console_sem)) | 1158 | if (down_trylock(&console_sem)) |
1058 | return -1; | 1159 | return 0; |
1059 | if (console_suspended) { | 1160 | if (console_suspended) { |
1060 | up(&console_sem); | 1161 | up(&console_sem); |
1061 | return -1; | 1162 | return 0; |
1062 | } | 1163 | } |
1063 | console_locked = 1; | 1164 | console_locked = 1; |
1064 | console_may_schedule = 0; | 1165 | console_may_schedule = 0; |
1065 | return 0; | 1166 | return 1; |
1066 | } | 1167 | } |
1067 | EXPORT_SYMBOL(try_acquire_console_sem); | 1168 | EXPORT_SYMBOL(console_trylock); |
1068 | 1169 | ||
1069 | int is_console_locked(void) | 1170 | int is_console_locked(void) |
1070 | { | 1171 | { |
@@ -1095,20 +1196,20 @@ void wake_up_klogd(void) | |||
1095 | } | 1196 | } |
1096 | 1197 | ||
1097 | /** | 1198 | /** |
1098 | * release_console_sem - unlock the console system | 1199 | * console_unlock - unlock the console system |
1099 | * | 1200 | * |
1100 | * Releases the semaphore which the caller holds on the console system | 1201 | * Releases the console_lock which the caller holds on the console system |
1101 | * and the console driver list. | 1202 | * and the console driver list. |
1102 | * | 1203 | * |
1103 | * While the semaphore was held, console output may have been buffered | 1204 | * While the console_lock was held, console output may have been buffered |
1104 | * by printk(). If this is the case, release_console_sem() emits | 1205 | * by printk(). If this is the case, console_unlock(); emits |
1105 | * the output prior to releasing the semaphore. | 1206 | * the output prior to releasing the lock. |
1106 | * | 1207 | * |
1107 | * If there is output waiting for klogd, we wake it up. | 1208 | * If there is output waiting for klogd, we wake it up. |
1108 | * | 1209 | * |
1109 | * release_console_sem() may be called from any context. | 1210 | * console_unlock(); may be called from any context. |
1110 | */ | 1211 | */ |
1111 | void release_console_sem(void) | 1212 | void console_unlock(void) |
1112 | { | 1213 | { |
1113 | unsigned long flags; | 1214 | unsigned long flags; |
1114 | unsigned _con_start, _log_end; | 1215 | unsigned _con_start, _log_end; |
@@ -1136,12 +1237,17 @@ void release_console_sem(void) | |||
1136 | local_irq_restore(flags); | 1237 | local_irq_restore(flags); |
1137 | } | 1238 | } |
1138 | 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 | |||
1139 | up(&console_sem); | 1245 | up(&console_sem); |
1140 | spin_unlock_irqrestore(&logbuf_lock, flags); | 1246 | spin_unlock_irqrestore(&logbuf_lock, flags); |
1141 | if (wake_klogd) | 1247 | if (wake_klogd) |
1142 | wake_up_klogd(); | 1248 | wake_up_klogd(); |
1143 | } | 1249 | } |
1144 | EXPORT_SYMBOL(release_console_sem); | 1250 | EXPORT_SYMBOL(console_unlock); |
1145 | 1251 | ||
1146 | /** | 1252 | /** |
1147 | * console_conditional_schedule - yield the CPU if required | 1253 | * console_conditional_schedule - yield the CPU if required |
@@ -1150,7 +1256,7 @@ EXPORT_SYMBOL(release_console_sem); | |||
1150 | * if this CPU should yield the CPU to another task, do | 1256 | * if this CPU should yield the CPU to another task, do |
1151 | * so here. | 1257 | * so here. |
1152 | * | 1258 | * |
1153 | * Must be called within acquire_console_sem(). | 1259 | * Must be called within console_lock();. |
1154 | */ | 1260 | */ |
1155 | void __sched console_conditional_schedule(void) | 1261 | void __sched console_conditional_schedule(void) |
1156 | { | 1262 | { |
@@ -1171,14 +1277,14 @@ void console_unblank(void) | |||
1171 | if (down_trylock(&console_sem) != 0) | 1277 | if (down_trylock(&console_sem) != 0) |
1172 | return; | 1278 | return; |
1173 | } else | 1279 | } else |
1174 | acquire_console_sem(); | 1280 | console_lock(); |
1175 | 1281 | ||
1176 | console_locked = 1; | 1282 | console_locked = 1; |
1177 | console_may_schedule = 0; | 1283 | console_may_schedule = 0; |
1178 | for_each_console(c) | 1284 | for_each_console(c) |
1179 | if ((c->flags & CON_ENABLED) && c->unblank) | 1285 | if ((c->flags & CON_ENABLED) && c->unblank) |
1180 | c->unblank(); | 1286 | c->unblank(); |
1181 | release_console_sem(); | 1287 | console_unlock(); |
1182 | } | 1288 | } |
1183 | 1289 | ||
1184 | /* | 1290 | /* |
@@ -1189,7 +1295,7 @@ struct tty_driver *console_device(int *index) | |||
1189 | struct console *c; | 1295 | struct console *c; |
1190 | struct tty_driver *driver = NULL; | 1296 | struct tty_driver *driver = NULL; |
1191 | 1297 | ||
1192 | acquire_console_sem(); | 1298 | console_lock(); |
1193 | for_each_console(c) { | 1299 | for_each_console(c) { |
1194 | if (!c->device) | 1300 | if (!c->device) |
1195 | continue; | 1301 | continue; |
@@ -1197,7 +1303,7 @@ struct tty_driver *console_device(int *index) | |||
1197 | if (driver) | 1303 | if (driver) |
1198 | break; | 1304 | break; |
1199 | } | 1305 | } |
1200 | release_console_sem(); | 1306 | console_unlock(); |
1201 | return driver; | 1307 | return driver; |
1202 | } | 1308 | } |
1203 | 1309 | ||
@@ -1208,20 +1314,32 @@ struct tty_driver *console_device(int *index) | |||
1208 | */ | 1314 | */ |
1209 | void console_stop(struct console *console) | 1315 | void console_stop(struct console *console) |
1210 | { | 1316 | { |
1211 | acquire_console_sem(); | 1317 | console_lock(); |
1212 | console->flags &= ~CON_ENABLED; | 1318 | console->flags &= ~CON_ENABLED; |
1213 | release_console_sem(); | 1319 | console_unlock(); |
1214 | } | 1320 | } |
1215 | EXPORT_SYMBOL(console_stop); | 1321 | EXPORT_SYMBOL(console_stop); |
1216 | 1322 | ||
1217 | void console_start(struct console *console) | 1323 | void console_start(struct console *console) |
1218 | { | 1324 | { |
1219 | acquire_console_sem(); | 1325 | console_lock(); |
1220 | console->flags |= CON_ENABLED; | 1326 | console->flags |= CON_ENABLED; |
1221 | release_console_sem(); | 1327 | console_unlock(); |
1222 | } | 1328 | } |
1223 | EXPORT_SYMBOL(console_start); | 1329 | EXPORT_SYMBOL(console_start); |
1224 | 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 | |||
1225 | /* | 1343 | /* |
1226 | * The console driver calls this routine during kernel initialization | 1344 | * The console driver calls this routine during kernel initialization |
1227 | * to register the console printing procedure with printk() and to | 1345 | * to register the console printing procedure with printk() and to |
@@ -1340,7 +1458,7 @@ void register_console(struct console *newcon) | |||
1340 | * Put this console in the list - keep the | 1458 | * Put this console in the list - keep the |
1341 | * preferred driver at the head of the list. | 1459 | * preferred driver at the head of the list. |
1342 | */ | 1460 | */ |
1343 | acquire_console_sem(); | 1461 | console_lock(); |
1344 | if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) { | 1462 | if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) { |
1345 | newcon->next = console_drivers; | 1463 | newcon->next = console_drivers; |
1346 | console_drivers = newcon; | 1464 | console_drivers = newcon; |
@@ -1352,14 +1470,20 @@ void register_console(struct console *newcon) | |||
1352 | } | 1470 | } |
1353 | if (newcon->flags & CON_PRINTBUFFER) { | 1471 | if (newcon->flags & CON_PRINTBUFFER) { |
1354 | /* | 1472 | /* |
1355 | * release_console_sem() will print out the buffered messages | 1473 | * console_unlock(); will print out the buffered messages |
1356 | * for us. | 1474 | * for us. |
1357 | */ | 1475 | */ |
1358 | spin_lock_irqsave(&logbuf_lock, flags); | 1476 | spin_lock_irqsave(&logbuf_lock, flags); |
1359 | con_start = log_start; | 1477 | con_start = log_start; |
1360 | 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; | ||
1361 | } | 1485 | } |
1362 | release_console_sem(); | 1486 | console_unlock(); |
1363 | console_sysfs_notify(); | 1487 | console_sysfs_notify(); |
1364 | 1488 | ||
1365 | /* | 1489 | /* |
@@ -1369,7 +1493,9 @@ void register_console(struct console *newcon) | |||
1369 | * 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 |
1370 | * 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) |
1371 | */ | 1495 | */ |
1372 | 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) { | ||
1373 | /* we need to iterate through twice, to make sure we print | 1499 | /* we need to iterate through twice, to make sure we print |
1374 | * everything out, before we unregister the console(s) | 1500 | * everything out, before we unregister the console(s) |
1375 | */ | 1501 | */ |
@@ -1396,7 +1522,7 @@ int unregister_console(struct console *console) | |||
1396 | return braille_unregister_console(console); | 1522 | return braille_unregister_console(console); |
1397 | #endif | 1523 | #endif |
1398 | 1524 | ||
1399 | acquire_console_sem(); | 1525 | console_lock(); |
1400 | if (console_drivers == console) { | 1526 | if (console_drivers == console) { |
1401 | console_drivers=console->next; | 1527 | console_drivers=console->next; |
1402 | res = 0; | 1528 | res = 0; |
@@ -1418,7 +1544,7 @@ int unregister_console(struct console *console) | |||
1418 | if (console_drivers != NULL && console->flags & CON_CONSDEV) | 1544 | if (console_drivers != NULL && console->flags & CON_CONSDEV) |
1419 | console_drivers->flags |= CON_CONSDEV; | 1545 | console_drivers->flags |= CON_CONSDEV; |
1420 | 1546 | ||
1421 | release_console_sem(); | 1547 | console_unlock(); |
1422 | console_sysfs_notify(); | 1548 | console_sysfs_notify(); |
1423 | return res; | 1549 | return res; |
1424 | } | 1550 | } |