diff options
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 315 |
1 files changed, 231 insertions, 84 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 2ddbdc73aade..35185392173f 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/smp.h> | 31 | #include <linux/smp.h> |
32 | #include <linux/security.h> | 32 | #include <linux/security.h> |
33 | #include <linux/bootmem.h> | 33 | #include <linux/bootmem.h> |
34 | #include <linux/memblock.h> | ||
34 | #include <linux/syscalls.h> | 35 | #include <linux/syscalls.h> |
35 | #include <linux/kexec.h> | 36 | #include <linux/kexec.h> |
36 | #include <linux/kdb.h> | 37 | #include <linux/kdb.h> |
@@ -53,7 +54,7 @@ void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...) | |||
53 | #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) | 54 | #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) |
54 | 55 | ||
55 | /* printk's without a loglevel use this.. */ | 56 | /* printk's without a loglevel use this.. */ |
56 | #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */ | 57 | #define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL |
57 | 58 | ||
58 | /* We show everything that is MORE important than this.. */ | 59 | /* We show everything that is MORE important than this.. */ |
59 | #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */ | 60 | #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */ |
@@ -113,6 +114,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 */ | 114 | static unsigned log_end; /* Index into log_buf: most-recently-written-char + 1 */ |
114 | 115 | ||
115 | /* | 116 | /* |
117 | * If exclusive_console is non-NULL then only this console is to be printed to. | ||
118 | */ | ||
119 | static struct console *exclusive_console; | ||
120 | |||
121 | /* | ||
116 | * Array of consoles built from command line options (console=) | 122 | * Array of consoles built from command line options (console=) |
117 | */ | 123 | */ |
118 | struct console_cmdline | 124 | struct console_cmdline |
@@ -162,46 +168,74 @@ void log_buf_kexec_setup(void) | |||
162 | } | 168 | } |
163 | #endif | 169 | #endif |
164 | 170 | ||
171 | /* requested log_buf_len from kernel cmdline */ | ||
172 | static unsigned long __initdata new_log_buf_len; | ||
173 | |||
174 | /* save requested log_buf_len since it's too early to process it */ | ||
165 | static int __init log_buf_len_setup(char *str) | 175 | static int __init log_buf_len_setup(char *str) |
166 | { | 176 | { |
167 | unsigned size = memparse(str, &str); | 177 | unsigned size = memparse(str, &str); |
168 | unsigned long flags; | ||
169 | 178 | ||
170 | if (size) | 179 | if (size) |
171 | size = roundup_pow_of_two(size); | 180 | size = roundup_pow_of_two(size); |
172 | if (size > log_buf_len) { | 181 | if (size > log_buf_len) |
173 | unsigned start, dest_idx, offset; | 182 | new_log_buf_len = size; |
174 | char *new_log_buf; | ||
175 | 183 | ||
176 | new_log_buf = alloc_bootmem(size); | 184 | return 0; |
177 | if (!new_log_buf) { | 185 | } |
178 | printk(KERN_WARNING "log_buf_len: allocation failed\n"); | 186 | early_param("log_buf_len", log_buf_len_setup); |
179 | goto out; | ||
180 | } | ||
181 | 187 | ||
182 | spin_lock_irqsave(&logbuf_lock, flags); | 188 | void __init setup_log_buf(int early) |
183 | log_buf_len = size; | 189 | { |
184 | log_buf = new_log_buf; | 190 | unsigned long flags; |
185 | 191 | unsigned start, dest_idx, offset; | |
186 | offset = start = min(con_start, log_start); | 192 | char *new_log_buf; |
187 | dest_idx = 0; | 193 | int free; |
188 | while (start != log_end) { | 194 | |
189 | log_buf[dest_idx] = __log_buf[start & (__LOG_BUF_LEN - 1)]; | 195 | if (!new_log_buf_len) |
190 | start++; | 196 | return; |
191 | dest_idx++; | 197 | |
192 | } | 198 | if (early) { |
193 | log_start -= offset; | 199 | unsigned long mem; |
194 | con_start -= offset; | ||
195 | log_end -= offset; | ||
196 | spin_unlock_irqrestore(&logbuf_lock, flags); | ||
197 | 200 | ||
198 | printk(KERN_NOTICE "log_buf_len: %d\n", log_buf_len); | 201 | mem = memblock_alloc(new_log_buf_len, PAGE_SIZE); |
202 | if (mem == MEMBLOCK_ERROR) | ||
203 | return; | ||
204 | new_log_buf = __va(mem); | ||
205 | } else { | ||
206 | new_log_buf = alloc_bootmem_nopanic(new_log_buf_len); | ||
199 | } | 207 | } |
200 | out: | ||
201 | return 1; | ||
202 | } | ||
203 | 208 | ||
204 | __setup("log_buf_len=", log_buf_len_setup); | 209 | if (unlikely(!new_log_buf)) { |
210 | pr_err("log_buf_len: %ld bytes not available\n", | ||
211 | new_log_buf_len); | ||
212 | return; | ||
213 | } | ||
214 | |||
215 | spin_lock_irqsave(&logbuf_lock, flags); | ||
216 | log_buf_len = new_log_buf_len; | ||
217 | log_buf = new_log_buf; | ||
218 | new_log_buf_len = 0; | ||
219 | free = __LOG_BUF_LEN - log_end; | ||
220 | |||
221 | offset = start = min(con_start, log_start); | ||
222 | dest_idx = 0; | ||
223 | while (start != log_end) { | ||
224 | unsigned log_idx_mask = start & (__LOG_BUF_LEN - 1); | ||
225 | |||
226 | log_buf[dest_idx] = __log_buf[log_idx_mask]; | ||
227 | start++; | ||
228 | dest_idx++; | ||
229 | } | ||
230 | log_start -= offset; | ||
231 | con_start -= offset; | ||
232 | log_end -= offset; | ||
233 | spin_unlock_irqrestore(&logbuf_lock, flags); | ||
234 | |||
235 | pr_info("log_buf_len: %d\n", log_buf_len); | ||
236 | pr_info("early log buf free: %d(%d%%)\n", | ||
237 | free, (free * 100) / __LOG_BUF_LEN); | ||
238 | } | ||
205 | 239 | ||
206 | #ifdef CONFIG_BOOT_PRINTK_DELAY | 240 | #ifdef CONFIG_BOOT_PRINTK_DELAY |
207 | 241 | ||
@@ -262,25 +296,47 @@ int dmesg_restrict = 1; | |||
262 | int dmesg_restrict; | 296 | int dmesg_restrict; |
263 | #endif | 297 | #endif |
264 | 298 | ||
299 | static int syslog_action_restricted(int type) | ||
300 | { | ||
301 | if (dmesg_restrict) | ||
302 | return 1; | ||
303 | /* Unless restricted, we allow "read all" and "get buffer size" for everybody */ | ||
304 | return type != SYSLOG_ACTION_READ_ALL && type != SYSLOG_ACTION_SIZE_BUFFER; | ||
305 | } | ||
306 | |||
307 | static int check_syslog_permissions(int type, bool from_file) | ||
308 | { | ||
309 | /* | ||
310 | * If this is from /proc/kmsg and we've already opened it, then we've | ||
311 | * already done the capabilities checks at open time. | ||
312 | */ | ||
313 | if (from_file && type != SYSLOG_ACTION_OPEN) | ||
314 | return 0; | ||
315 | |||
316 | if (syslog_action_restricted(type)) { | ||
317 | if (capable(CAP_SYSLOG)) | ||
318 | return 0; | ||
319 | /* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */ | ||
320 | if (capable(CAP_SYS_ADMIN)) { | ||
321 | WARN_ONCE(1, "Attempt to access syslog with CAP_SYS_ADMIN " | ||
322 | "but no CAP_SYSLOG (deprecated).\n"); | ||
323 | return 0; | ||
324 | } | ||
325 | return -EPERM; | ||
326 | } | ||
327 | return 0; | ||
328 | } | ||
329 | |||
265 | int do_syslog(int type, char __user *buf, int len, bool from_file) | 330 | int do_syslog(int type, char __user *buf, int len, bool from_file) |
266 | { | 331 | { |
267 | unsigned i, j, limit, count; | 332 | unsigned i, j, limit, count; |
268 | int do_clear = 0; | 333 | int do_clear = 0; |
269 | char c; | 334 | char c; |
270 | int error = 0; | 335 | int error; |
271 | 336 | ||
272 | /* | 337 | error = check_syslog_permissions(type, from_file); |
273 | * If this is from /proc/kmsg we only do the capabilities checks | 338 | if (error) |
274 | * at open time. | 339 | 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 | 340 | ||
285 | error = security_syslog(type); | 341 | error = security_syslog(type); |
286 | if (error) | 342 | if (error) |
@@ -423,12 +479,6 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) | |||
423 | } | 479 | } |
424 | out: | 480 | out: |
425 | return error; | 481 | 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 | } | 482 | } |
433 | 483 | ||
434 | SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) | 484 | SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) |
@@ -460,6 +510,8 @@ static void __call_console_drivers(unsigned start, unsigned end) | |||
460 | struct console *con; | 510 | struct console *con; |
461 | 511 | ||
462 | for_each_console(con) { | 512 | for_each_console(con) { |
513 | if (exclusive_console && con != exclusive_console) | ||
514 | continue; | ||
463 | if ((con->flags & CON_ENABLED) && con->write && | 515 | if ((con->flags & CON_ENABLED) && con->write && |
464 | (cpu_online(smp_processor_id()) || | 516 | (cpu_online(smp_processor_id()) || |
465 | (con->flags & CON_ANYTIME))) | 517 | (con->flags & CON_ANYTIME))) |
@@ -499,6 +551,71 @@ static void _call_console_drivers(unsigned start, | |||
499 | } | 551 | } |
500 | 552 | ||
501 | /* | 553 | /* |
554 | * Parse the syslog header <[0-9]*>. The decimal value represents 32bit, the | ||
555 | * lower 3 bit are the log level, the rest are the log facility. In case | ||
556 | * userspace passes usual userspace syslog messages to /dev/kmsg or | ||
557 | * /dev/ttyprintk, the log prefix might contain the facility. Printk needs | ||
558 | * to extract the correct log level for in-kernel processing, and not mangle | ||
559 | * the original value. | ||
560 | * | ||
561 | * If a prefix is found, the length of the prefix is returned. If 'level' is | ||
562 | * passed, it will be filled in with the log level without a possible facility | ||
563 | * value. If 'special' is passed, the special printk prefix chars are accepted | ||
564 | * and returned. If no valid header is found, 0 is returned and the passed | ||
565 | * variables are not touched. | ||
566 | */ | ||
567 | static size_t log_prefix(const char *p, unsigned int *level, char *special) | ||
568 | { | ||
569 | unsigned int lev = 0; | ||
570 | char sp = '\0'; | ||
571 | size_t len; | ||
572 | |||
573 | if (p[0] != '<' || !p[1]) | ||
574 | return 0; | ||
575 | if (p[2] == '>') { | ||
576 | /* usual single digit level number or special char */ | ||
577 | switch (p[1]) { | ||
578 | case '0' ... '7': | ||
579 | lev = p[1] - '0'; | ||
580 | break; | ||
581 | case 'c': /* KERN_CONT */ | ||
582 | case 'd': /* KERN_DEFAULT */ | ||
583 | sp = p[1]; | ||
584 | break; | ||
585 | default: | ||
586 | return 0; | ||
587 | } | ||
588 | len = 3; | ||
589 | } else { | ||
590 | /* multi digit including the level and facility number */ | ||
591 | char *endp = NULL; | ||
592 | |||
593 | if (p[1] < '0' && p[1] > '9') | ||
594 | return 0; | ||
595 | |||
596 | lev = (simple_strtoul(&p[1], &endp, 10) & 7); | ||
597 | if (endp == NULL || endp[0] != '>') | ||
598 | return 0; | ||
599 | len = (endp + 1) - p; | ||
600 | } | ||
601 | |||
602 | /* do not accept special char if not asked for */ | ||
603 | if (sp && !special) | ||
604 | return 0; | ||
605 | |||
606 | if (special) { | ||
607 | *special = sp; | ||
608 | /* return special char, do not touch level */ | ||
609 | if (sp) | ||
610 | return len; | ||
611 | } | ||
612 | |||
613 | if (level) | ||
614 | *level = lev; | ||
615 | return len; | ||
616 | } | ||
617 | |||
618 | /* | ||
502 | * Call the console drivers, asking them to write out | 619 | * Call the console drivers, asking them to write out |
503 | * log_buf[start] to log_buf[end - 1]. | 620 | * log_buf[start] to log_buf[end - 1]. |
504 | * The console_lock must be held. | 621 | * The console_lock must be held. |
@@ -513,13 +630,9 @@ static void call_console_drivers(unsigned start, unsigned end) | |||
513 | cur_index = start; | 630 | cur_index = start; |
514 | start_print = start; | 631 | start_print = start; |
515 | while (cur_index != end) { | 632 | while (cur_index != end) { |
516 | if (msg_level < 0 && ((end - cur_index) > 2) && | 633 | if (msg_level < 0 && ((end - cur_index) > 2)) { |
517 | LOG_BUF(cur_index + 0) == '<' && | 634 | /* strip log prefix */ |
518 | LOG_BUF(cur_index + 1) >= '0' && | 635 | 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; | 636 | start_print = cur_index; |
524 | } | 637 | } |
525 | while (cur_index != end) { | 638 | while (cur_index != end) { |
@@ -717,6 +830,8 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
717 | unsigned long flags; | 830 | unsigned long flags; |
718 | int this_cpu; | 831 | int this_cpu; |
719 | char *p; | 832 | char *p; |
833 | size_t plen; | ||
834 | char special; | ||
720 | 835 | ||
721 | boot_delay_msec(); | 836 | boot_delay_msec(); |
722 | printk_delay(); | 837 | printk_delay(); |
@@ -757,45 +872,52 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
757 | printed_len += vscnprintf(printk_buf + printed_len, | 872 | printed_len += vscnprintf(printk_buf + printed_len, |
758 | sizeof(printk_buf) - printed_len, fmt, args); | 873 | sizeof(printk_buf) - printed_len, fmt, args); |
759 | 874 | ||
760 | |||
761 | p = printk_buf; | 875 | p = printk_buf; |
762 | 876 | ||
763 | /* Do we have a loglevel in the string? */ | 877 | /* Read log level and handle special printk prefix */ |
764 | if (p[0] == '<') { | 878 | plen = log_prefix(p, ¤t_log_level, &special); |
765 | unsigned char c = p[1]; | 879 | if (plen) { |
766 | if (c && p[2] == '>') { | 880 | p += plen; |
767 | switch (c) { | 881 | |
768 | case '0' ... '7': /* loglevel */ | 882 | switch (special) { |
769 | current_log_level = c - '0'; | 883 | case 'c': /* Strip <c> KERN_CONT, continue line */ |
770 | /* Fallthrough - make sure we're on a new line */ | 884 | plen = 0; |
771 | case 'd': /* KERN_DEFAULT */ | 885 | break; |
772 | if (!new_text_line) { | 886 | case 'd': /* Strip <d> KERN_DEFAULT, start new line */ |
773 | emit_log_char('\n'); | 887 | plen = 0; |
774 | new_text_line = 1; | 888 | default: |
775 | } | 889 | if (!new_text_line) { |
776 | /* Fallthrough - skip the loglevel */ | 890 | emit_log_char('\n'); |
777 | case 'c': /* KERN_CONT */ | 891 | new_text_line = 1; |
778 | p += 3; | ||
779 | break; | ||
780 | } | 892 | } |
781 | } | 893 | } |
782 | } | 894 | } |
783 | 895 | ||
784 | /* | 896 | /* |
785 | * Copy the output into log_buf. If the caller didn't provide | 897 | * Copy the output into log_buf. If the caller didn't provide |
786 | * appropriate log level tags, we insert them here | 898 | * the appropriate log prefix, we insert them here |
787 | */ | 899 | */ |
788 | for ( ; *p; p++) { | 900 | for (; *p; p++) { |
789 | if (new_text_line) { | 901 | 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; | 902 | new_text_line = 0; |
796 | 903 | ||
904 | if (plen) { | ||
905 | /* Copy original log prefix */ | ||
906 | int i; | ||
907 | |||
908 | for (i = 0; i < plen; i++) | ||
909 | emit_log_char(printk_buf[i]); | ||
910 | printed_len += plen; | ||
911 | } else { | ||
912 | /* Add log prefix */ | ||
913 | emit_log_char('<'); | ||
914 | emit_log_char(current_log_level + '0'); | ||
915 | emit_log_char('>'); | ||
916 | printed_len += 3; | ||
917 | } | ||
918 | |||
797 | if (printk_time) { | 919 | if (printk_time) { |
798 | /* Follow the token with the time */ | 920 | /* Add the current time stamp */ |
799 | char tbuf[50], *tp; | 921 | char tbuf[50], *tp; |
800 | unsigned tlen; | 922 | unsigned tlen; |
801 | unsigned long long t; | 923 | unsigned long long t; |
@@ -1144,6 +1266,11 @@ void console_unlock(void) | |||
1144 | local_irq_restore(flags); | 1266 | local_irq_restore(flags); |
1145 | } | 1267 | } |
1146 | console_locked = 0; | 1268 | console_locked = 0; |
1269 | |||
1270 | /* Release the exclusive_console once it is used */ | ||
1271 | if (unlikely(exclusive_console)) | ||
1272 | exclusive_console = NULL; | ||
1273 | |||
1147 | up(&console_sem); | 1274 | up(&console_sem); |
1148 | spin_unlock_irqrestore(&logbuf_lock, flags); | 1275 | spin_unlock_irqrestore(&logbuf_lock, flags); |
1149 | if (wake_klogd) | 1276 | if (wake_klogd) |
@@ -1230,6 +1357,18 @@ void console_start(struct console *console) | |||
1230 | } | 1357 | } |
1231 | EXPORT_SYMBOL(console_start); | 1358 | EXPORT_SYMBOL(console_start); |
1232 | 1359 | ||
1360 | static int __read_mostly keep_bootcon; | ||
1361 | |||
1362 | static int __init keep_bootcon_setup(char *str) | ||
1363 | { | ||
1364 | keep_bootcon = 1; | ||
1365 | printk(KERN_INFO "debug: skip boot console de-registration.\n"); | ||
1366 | |||
1367 | return 0; | ||
1368 | } | ||
1369 | |||
1370 | early_param("keep_bootcon", keep_bootcon_setup); | ||
1371 | |||
1233 | /* | 1372 | /* |
1234 | * The console driver calls this routine during kernel initialization | 1373 | * The console driver calls this routine during kernel initialization |
1235 | * to register the console printing procedure with printk() and to | 1374 | * to register the console printing procedure with printk() and to |
@@ -1366,6 +1505,12 @@ void register_console(struct console *newcon) | |||
1366 | spin_lock_irqsave(&logbuf_lock, flags); | 1505 | spin_lock_irqsave(&logbuf_lock, flags); |
1367 | con_start = log_start; | 1506 | con_start = log_start; |
1368 | spin_unlock_irqrestore(&logbuf_lock, flags); | 1507 | spin_unlock_irqrestore(&logbuf_lock, flags); |
1508 | /* | ||
1509 | * We're about to replay the log buffer. Only do this to the | ||
1510 | * just-registered console to avoid excessive message spam to | ||
1511 | * the already-registered consoles. | ||
1512 | */ | ||
1513 | exclusive_console = newcon; | ||
1369 | } | 1514 | } |
1370 | console_unlock(); | 1515 | console_unlock(); |
1371 | console_sysfs_notify(); | 1516 | console_sysfs_notify(); |
@@ -1377,7 +1522,9 @@ void register_console(struct console *newcon) | |||
1377 | * users know there might be something in the kernel's log buffer that | 1522 | * users know there might be something in the kernel's log buffer that |
1378 | * went to the bootconsole (that they do not see on the real console) | 1523 | * went to the bootconsole (that they do not see on the real console) |
1379 | */ | 1524 | */ |
1380 | if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) { | 1525 | if (bcon && |
1526 | ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV) && | ||
1527 | !keep_bootcon) { | ||
1381 | /* we need to iterate through twice, to make sure we print | 1528 | /* we need to iterate through twice, to make sure we print |
1382 | * everything out, before we unregister the console(s) | 1529 | * everything out, before we unregister the console(s) |
1383 | */ | 1530 | */ |