diff options
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 182 |
1 files changed, 148 insertions, 34 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 6712a252b306..ee54355cfdf1 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -33,6 +33,9 @@ | |||
33 | #include <linux/bootmem.h> | 33 | #include <linux/bootmem.h> |
34 | #include <linux/syscalls.h> | 34 | #include <linux/syscalls.h> |
35 | #include <linux/kexec.h> | 35 | #include <linux/kexec.h> |
36 | #include <linux/ratelimit.h> | ||
37 | #include <linux/kmsg_dump.h> | ||
38 | #include <linux/syslog.h> | ||
36 | 39 | ||
37 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
38 | 41 | ||
@@ -67,8 +70,6 @@ int console_printk[4] = { | |||
67 | DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */ | 70 | DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */ |
68 | }; | 71 | }; |
69 | 72 | ||
70 | static int saved_console_loglevel = -1; | ||
71 | |||
72 | /* | 73 | /* |
73 | * divert printk() messages when there is a LITMUS^RT debug listener | 74 | * divert printk() messages when there is a LITMUS^RT debug listener |
74 | */ | 75 | */ |
@@ -150,6 +151,7 @@ static char __log_buf[__LOG_BUF_LEN]; | |||
150 | static char *log_buf = __log_buf; | 151 | static char *log_buf = __log_buf; |
151 | static int log_buf_len = __LOG_BUF_LEN; | 152 | static int log_buf_len = __LOG_BUF_LEN; |
152 | static unsigned logged_chars; /* Number of chars produced since last read+clear operation */ | 153 | static unsigned logged_chars; /* Number of chars produced since last read+clear operation */ |
154 | static int saved_console_loglevel = -1; | ||
153 | 155 | ||
154 | #ifdef CONFIG_KEXEC | 156 | #ifdef CONFIG_KEXEC |
155 | /* | 157 | /* |
@@ -263,38 +265,23 @@ static inline void boot_delay_msec(void) | |||
263 | } | 265 | } |
264 | #endif | 266 | #endif |
265 | 267 | ||
266 | /* | 268 | int do_syslog(int type, char __user *buf, int len, bool from_file) |
267 | * Commands to do_syslog: | ||
268 | * | ||
269 | * 0 -- Close the log. Currently a NOP. | ||
270 | * 1 -- Open the log. Currently a NOP. | ||
271 | * 2 -- Read from the log. | ||
272 | * 3 -- Read all messages remaining in the ring buffer. | ||
273 | * 4 -- Read and clear all messages remaining in the ring buffer | ||
274 | * 5 -- Clear ring buffer. | ||
275 | * 6 -- Disable printk's to console | ||
276 | * 7 -- Enable printk's to console | ||
277 | * 8 -- Set level of messages printed to console | ||
278 | * 9 -- Return number of unread characters in the log buffer | ||
279 | * 10 -- Return size of the log buffer | ||
280 | */ | ||
281 | int do_syslog(int type, char __user *buf, int len) | ||
282 | { | 269 | { |
283 | unsigned i, j, limit, count; | 270 | unsigned i, j, limit, count; |
284 | int do_clear = 0; | 271 | int do_clear = 0; |
285 | char c; | 272 | char c; |
286 | int error = 0; | 273 | int error = 0; |
287 | 274 | ||
288 | error = security_syslog(type); | 275 | error = security_syslog(type, from_file); |
289 | if (error) | 276 | if (error) |
290 | return error; | 277 | return error; |
291 | 278 | ||
292 | switch (type) { | 279 | switch (type) { |
293 | case 0: /* Close log */ | 280 | case SYSLOG_ACTION_CLOSE: /* Close log */ |
294 | break; | 281 | break; |
295 | case 1: /* Open log */ | 282 | case SYSLOG_ACTION_OPEN: /* Open log */ |
296 | break; | 283 | break; |
297 | case 2: /* Read from log */ | 284 | case SYSLOG_ACTION_READ: /* Read from log */ |
298 | error = -EINVAL; | 285 | error = -EINVAL; |
299 | if (!buf || len < 0) | 286 | if (!buf || len < 0) |
300 | goto out; | 287 | goto out; |
@@ -325,10 +312,12 @@ int do_syslog(int type, char __user *buf, int len) | |||
325 | if (!error) | 312 | if (!error) |
326 | error = i; | 313 | error = i; |
327 | break; | 314 | break; |
328 | case 4: /* Read/clear last kernel messages */ | 315 | /* Read/clear last kernel messages */ |
316 | case SYSLOG_ACTION_READ_CLEAR: | ||
329 | do_clear = 1; | 317 | do_clear = 1; |
330 | /* FALL THRU */ | 318 | /* FALL THRU */ |
331 | case 3: /* Read last kernel messages */ | 319 | /* Read last kernel messages */ |
320 | case SYSLOG_ACTION_READ_ALL: | ||
332 | error = -EINVAL; | 321 | error = -EINVAL; |
333 | if (!buf || len < 0) | 322 | if (!buf || len < 0) |
334 | goto out; | 323 | goto out; |
@@ -381,21 +370,25 @@ int do_syslog(int type, char __user *buf, int len) | |||
381 | } | 370 | } |
382 | } | 371 | } |
383 | break; | 372 | break; |
384 | case 5: /* Clear ring buffer */ | 373 | /* Clear ring buffer */ |
374 | case SYSLOG_ACTION_CLEAR: | ||
385 | logged_chars = 0; | 375 | logged_chars = 0; |
386 | break; | 376 | break; |
387 | case 6: /* Disable logging to console */ | 377 | /* Disable logging to console */ |
378 | case SYSLOG_ACTION_CONSOLE_OFF: | ||
388 | if (saved_console_loglevel == -1) | 379 | if (saved_console_loglevel == -1) |
389 | saved_console_loglevel = console_loglevel; | 380 | saved_console_loglevel = console_loglevel; |
390 | console_loglevel = minimum_console_loglevel; | 381 | console_loglevel = minimum_console_loglevel; |
391 | break; | 382 | break; |
392 | case 7: /* Enable logging to console */ | 383 | /* Enable logging to console */ |
384 | case SYSLOG_ACTION_CONSOLE_ON: | ||
393 | if (saved_console_loglevel != -1) { | 385 | if (saved_console_loglevel != -1) { |
394 | console_loglevel = saved_console_loglevel; | 386 | console_loglevel = saved_console_loglevel; |
395 | saved_console_loglevel = -1; | 387 | saved_console_loglevel = -1; |
396 | } | 388 | } |
397 | break; | 389 | break; |
398 | case 8: /* Set level of messages printed to console */ | 390 | /* Set level of messages printed to console */ |
391 | case SYSLOG_ACTION_CONSOLE_LEVEL: | ||
399 | error = -EINVAL; | 392 | error = -EINVAL; |
400 | if (len < 1 || len > 8) | 393 | if (len < 1 || len > 8) |
401 | goto out; | 394 | goto out; |
@@ -406,10 +399,12 @@ int do_syslog(int type, char __user *buf, int len) | |||
406 | saved_console_loglevel = -1; | 399 | saved_console_loglevel = -1; |
407 | error = 0; | 400 | error = 0; |
408 | break; | 401 | break; |
409 | case 9: /* Number of chars in the log buffer */ | 402 | /* Number of chars in the log buffer */ |
403 | case SYSLOG_ACTION_SIZE_UNREAD: | ||
410 | error = log_end - log_start; | 404 | error = log_end - log_start; |
411 | break; | 405 | break; |
412 | case 10: /* Size of the log buffer */ | 406 | /* Size of the log buffer */ |
407 | case SYSLOG_ACTION_SIZE_BUFFER: | ||
413 | error = log_buf_len; | 408 | error = log_buf_len; |
414 | break; | 409 | break; |
415 | default: | 410 | default: |
@@ -422,7 +417,7 @@ out: | |||
422 | 417 | ||
423 | SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) | 418 | SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) |
424 | { | 419 | { |
425 | return do_syslog(type, buf, len); | 420 | return do_syslog(type, buf, len, SYSLOG_FROM_CALL); |
426 | } | 421 | } |
427 | 422 | ||
428 | /* | 423 | /* |
@@ -1386,11 +1381,11 @@ late_initcall(disable_boot_consoles); | |||
1386 | */ | 1381 | */ |
1387 | DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10); | 1382 | DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10); |
1388 | 1383 | ||
1389 | int printk_ratelimit(void) | 1384 | int __printk_ratelimit(const char *func) |
1390 | { | 1385 | { |
1391 | return __ratelimit(&printk_ratelimit_state); | 1386 | return ___ratelimit(&printk_ratelimit_state, func); |
1392 | } | 1387 | } |
1393 | EXPORT_SYMBOL(printk_ratelimit); | 1388 | EXPORT_SYMBOL(__printk_ratelimit); |
1394 | 1389 | ||
1395 | /** | 1390 | /** |
1396 | * printk_timed_ratelimit - caller-controlled printk ratelimiting | 1391 | * printk_timed_ratelimit - caller-controlled printk ratelimiting |
@@ -1414,4 +1409,123 @@ bool printk_timed_ratelimit(unsigned long *caller_jiffies, | |||
1414 | return false; | 1409 | return false; |
1415 | } | 1410 | } |
1416 | EXPORT_SYMBOL(printk_timed_ratelimit); | 1411 | EXPORT_SYMBOL(printk_timed_ratelimit); |
1412 | |||
1413 | static DEFINE_SPINLOCK(dump_list_lock); | ||
1414 | static LIST_HEAD(dump_list); | ||
1415 | |||
1416 | /** | ||
1417 | * kmsg_dump_register - register a kernel log dumper. | ||
1418 | * @dumper: pointer to the kmsg_dumper structure | ||
1419 | * | ||
1420 | * Adds a kernel log dumper to the system. The dump callback in the | ||
1421 | * structure will be called when the kernel oopses or panics and must be | ||
1422 | * set. Returns zero on success and %-EINVAL or %-EBUSY otherwise. | ||
1423 | */ | ||
1424 | int kmsg_dump_register(struct kmsg_dumper *dumper) | ||
1425 | { | ||
1426 | unsigned long flags; | ||
1427 | int err = -EBUSY; | ||
1428 | |||
1429 | /* The dump callback needs to be set */ | ||
1430 | if (!dumper->dump) | ||
1431 | return -EINVAL; | ||
1432 | |||
1433 | spin_lock_irqsave(&dump_list_lock, flags); | ||
1434 | /* Don't allow registering multiple times */ | ||
1435 | if (!dumper->registered) { | ||
1436 | dumper->registered = 1; | ||
1437 | list_add_tail(&dumper->list, &dump_list); | ||
1438 | err = 0; | ||
1439 | } | ||
1440 | spin_unlock_irqrestore(&dump_list_lock, flags); | ||
1441 | |||
1442 | return err; | ||
1443 | } | ||
1444 | EXPORT_SYMBOL_GPL(kmsg_dump_register); | ||
1445 | |||
1446 | /** | ||
1447 | * kmsg_dump_unregister - unregister a kmsg dumper. | ||
1448 | * @dumper: pointer to the kmsg_dumper structure | ||
1449 | * | ||
1450 | * Removes a dump device from the system. Returns zero on success and | ||
1451 | * %-EINVAL otherwise. | ||
1452 | */ | ||
1453 | int kmsg_dump_unregister(struct kmsg_dumper *dumper) | ||
1454 | { | ||
1455 | unsigned long flags; | ||
1456 | int err = -EINVAL; | ||
1457 | |||
1458 | spin_lock_irqsave(&dump_list_lock, flags); | ||
1459 | if (dumper->registered) { | ||
1460 | dumper->registered = 0; | ||
1461 | list_del(&dumper->list); | ||
1462 | err = 0; | ||
1463 | } | ||
1464 | spin_unlock_irqrestore(&dump_list_lock, flags); | ||
1465 | |||
1466 | return err; | ||
1467 | } | ||
1468 | EXPORT_SYMBOL_GPL(kmsg_dump_unregister); | ||
1469 | |||
1470 | static const char const *kmsg_reasons[] = { | ||
1471 | [KMSG_DUMP_OOPS] = "oops", | ||
1472 | [KMSG_DUMP_PANIC] = "panic", | ||
1473 | [KMSG_DUMP_KEXEC] = "kexec", | ||
1474 | }; | ||
1475 | |||
1476 | static const char *kmsg_to_str(enum kmsg_dump_reason reason) | ||
1477 | { | ||
1478 | if (reason >= ARRAY_SIZE(kmsg_reasons) || reason < 0) | ||
1479 | return "unknown"; | ||
1480 | |||
1481 | return kmsg_reasons[reason]; | ||
1482 | } | ||
1483 | |||
1484 | /** | ||
1485 | * kmsg_dump - dump kernel log to kernel message dumpers. | ||
1486 | * @reason: the reason (oops, panic etc) for dumping | ||
1487 | * | ||
1488 | * Iterate through each of the dump devices and call the oops/panic | ||
1489 | * callbacks with the log buffer. | ||
1490 | */ | ||
1491 | void kmsg_dump(enum kmsg_dump_reason reason) | ||
1492 | { | ||
1493 | unsigned long end; | ||
1494 | unsigned chars; | ||
1495 | struct kmsg_dumper *dumper; | ||
1496 | const char *s1, *s2; | ||
1497 | unsigned long l1, l2; | ||
1498 | unsigned long flags; | ||
1499 | |||
1500 | /* Theoretically, the log could move on after we do this, but | ||
1501 | there's not a lot we can do about that. The new messages | ||
1502 | will overwrite the start of what we dump. */ | ||
1503 | spin_lock_irqsave(&logbuf_lock, flags); | ||
1504 | end = log_end & LOG_BUF_MASK; | ||
1505 | chars = logged_chars; | ||
1506 | spin_unlock_irqrestore(&logbuf_lock, flags); | ||
1507 | |||
1508 | if (logged_chars > end) { | ||
1509 | s1 = log_buf + log_buf_len - logged_chars + end; | ||
1510 | l1 = logged_chars - end; | ||
1511 | |||
1512 | s2 = log_buf; | ||
1513 | l2 = end; | ||
1514 | } else { | ||
1515 | s1 = ""; | ||
1516 | l1 = 0; | ||
1517 | |||
1518 | s2 = log_buf + end - logged_chars; | ||
1519 | l2 = logged_chars; | ||
1520 | } | ||
1521 | |||
1522 | if (!spin_trylock_irqsave(&dump_list_lock, flags)) { | ||
1523 | printk(KERN_ERR "dump_kmsg: dump list lock is held during %s, skipping dump\n", | ||
1524 | kmsg_to_str(reason)); | ||
1525 | return; | ||
1526 | } | ||
1527 | list_for_each_entry(dumper, &dump_list, list) | ||
1528 | dumper->dump(dumper, reason, s1, l1, s2, l2); | ||
1529 | spin_unlock_irqrestore(&dump_list_lock, flags); | ||
1530 | } | ||
1417 | #endif | 1531 | #endif |