diff options
Diffstat (limited to 'kernel/printk.c')
| -rw-r--r-- | kernel/printk.c | 727 |
1 files changed, 554 insertions, 173 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index 32462d2b364a..ac4bc9e79465 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
| @@ -193,12 +193,21 @@ static int console_may_schedule; | |||
| 193 | * separated by ',', and find the message after the ';' character. | 193 | * separated by ',', and find the message after the ';' character. |
| 194 | */ | 194 | */ |
| 195 | 195 | ||
| 196 | enum log_flags { | ||
| 197 | LOG_NOCONS = 1, /* already flushed, do not print to console */ | ||
| 198 | LOG_NEWLINE = 2, /* text ended with a newline */ | ||
| 199 | LOG_PREFIX = 4, /* text started with a prefix */ | ||
| 200 | LOG_CONT = 8, /* text is a fragment of a continuation line */ | ||
| 201 | }; | ||
| 202 | |||
| 196 | struct log { | 203 | struct log { |
| 197 | u64 ts_nsec; /* timestamp in nanoseconds */ | 204 | u64 ts_nsec; /* timestamp in nanoseconds */ |
| 198 | u16 len; /* length of entire record */ | 205 | u16 len; /* length of entire record */ |
| 199 | u16 text_len; /* length of text buffer */ | 206 | u16 text_len; /* length of text buffer */ |
| 200 | u16 dict_len; /* length of dictionary buffer */ | 207 | u16 dict_len; /* length of dictionary buffer */ |
| 201 | u16 level; /* syslog level + facility */ | 208 | u8 facility; /* syslog facility */ |
| 209 | u8 flags:5; /* internal record flags */ | ||
| 210 | u8 level:3; /* syslog level */ | ||
| 202 | }; | 211 | }; |
| 203 | 212 | ||
| 204 | /* | 213 | /* |
| @@ -210,6 +219,8 @@ static DEFINE_RAW_SPINLOCK(logbuf_lock); | |||
| 210 | /* the next printk record to read by syslog(READ) or /proc/kmsg */ | 219 | /* the next printk record to read by syslog(READ) or /proc/kmsg */ |
| 211 | static u64 syslog_seq; | 220 | static u64 syslog_seq; |
| 212 | static u32 syslog_idx; | 221 | static u32 syslog_idx; |
| 222 | static enum log_flags syslog_prev; | ||
| 223 | static size_t syslog_partial; | ||
| 213 | 224 | ||
| 214 | /* index and sequence number of the first record stored in the buffer */ | 225 | /* index and sequence number of the first record stored in the buffer */ |
| 215 | static u64 log_first_seq; | 226 | static u64 log_first_seq; |
| @@ -227,10 +238,10 @@ static u32 clear_idx; | |||
| 227 | #define LOG_LINE_MAX 1024 | 238 | #define LOG_LINE_MAX 1024 |
| 228 | 239 | ||
| 229 | /* record buffer */ | 240 | /* record buffer */ |
| 230 | #if !defined(CONFIG_64BIT) || defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) | 241 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) |
| 231 | #define LOG_ALIGN 4 | 242 | #define LOG_ALIGN 4 |
| 232 | #else | 243 | #else |
| 233 | #define LOG_ALIGN 8 | 244 | #define LOG_ALIGN __alignof__(struct log) |
| 234 | #endif | 245 | #endif |
| 235 | #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) | 246 | #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) |
| 236 | static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN); | 247 | static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN); |
| @@ -286,6 +297,7 @@ static u32 log_next(u32 idx) | |||
| 286 | 297 | ||
| 287 | /* insert record into the buffer, discard old ones, update heads */ | 298 | /* insert record into the buffer, discard old ones, update heads */ |
| 288 | static void log_store(int facility, int level, | 299 | static void log_store(int facility, int level, |
| 300 | enum log_flags flags, u64 ts_nsec, | ||
| 289 | const char *dict, u16 dict_len, | 301 | const char *dict, u16 dict_len, |
| 290 | const char *text, u16 text_len) | 302 | const char *text, u16 text_len) |
| 291 | { | 303 | { |
| @@ -329,8 +341,13 @@ static void log_store(int facility, int level, | |||
| 329 | msg->text_len = text_len; | 341 | msg->text_len = text_len; |
| 330 | memcpy(log_dict(msg), dict, dict_len); | 342 | memcpy(log_dict(msg), dict, dict_len); |
| 331 | msg->dict_len = dict_len; | 343 | msg->dict_len = dict_len; |
| 332 | msg->level = (facility << 3) | (level & 7); | 344 | msg->facility = facility; |
| 333 | msg->ts_nsec = local_clock(); | 345 | msg->level = level & 7; |
| 346 | msg->flags = flags & 0x1f; | ||
| 347 | if (ts_nsec > 0) | ||
| 348 | msg->ts_nsec = ts_nsec; | ||
| 349 | else | ||
| 350 | msg->ts_nsec = local_clock(); | ||
| 334 | memset(log_dict(msg) + dict_len, 0, pad_len); | 351 | memset(log_dict(msg) + dict_len, 0, pad_len); |
| 335 | msg->len = sizeof(struct log) + text_len + dict_len + pad_len; | 352 | msg->len = sizeof(struct log) + text_len + dict_len + pad_len; |
| 336 | 353 | ||
| @@ -414,21 +431,23 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, | |||
| 414 | if (!user) | 431 | if (!user) |
| 415 | return -EBADF; | 432 | return -EBADF; |
| 416 | 433 | ||
| 417 | mutex_lock(&user->lock); | 434 | ret = mutex_lock_interruptible(&user->lock); |
| 418 | raw_spin_lock(&logbuf_lock); | 435 | if (ret) |
| 436 | return ret; | ||
| 437 | raw_spin_lock_irq(&logbuf_lock); | ||
| 419 | while (user->seq == log_next_seq) { | 438 | while (user->seq == log_next_seq) { |
| 420 | if (file->f_flags & O_NONBLOCK) { | 439 | if (file->f_flags & O_NONBLOCK) { |
| 421 | ret = -EAGAIN; | 440 | ret = -EAGAIN; |
| 422 | raw_spin_unlock(&logbuf_lock); | 441 | raw_spin_unlock_irq(&logbuf_lock); |
| 423 | goto out; | 442 | goto out; |
| 424 | } | 443 | } |
| 425 | 444 | ||
| 426 | raw_spin_unlock(&logbuf_lock); | 445 | raw_spin_unlock_irq(&logbuf_lock); |
| 427 | ret = wait_event_interruptible(log_wait, | 446 | ret = wait_event_interruptible(log_wait, |
| 428 | user->seq != log_next_seq); | 447 | user->seq != log_next_seq); |
| 429 | if (ret) | 448 | if (ret) |
| 430 | goto out; | 449 | goto out; |
| 431 | raw_spin_lock(&logbuf_lock); | 450 | raw_spin_lock_irq(&logbuf_lock); |
| 432 | } | 451 | } |
| 433 | 452 | ||
| 434 | if (user->seq < log_first_seq) { | 453 | if (user->seq < log_first_seq) { |
| @@ -436,7 +455,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, | |||
| 436 | user->idx = log_first_idx; | 455 | user->idx = log_first_idx; |
| 437 | user->seq = log_first_seq; | 456 | user->seq = log_first_seq; |
| 438 | ret = -EPIPE; | 457 | ret = -EPIPE; |
| 439 | raw_spin_unlock(&logbuf_lock); | 458 | raw_spin_unlock_irq(&logbuf_lock); |
| 440 | goto out; | 459 | goto out; |
| 441 | } | 460 | } |
| 442 | 461 | ||
| @@ -444,13 +463,13 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, | |||
| 444 | ts_usec = msg->ts_nsec; | 463 | ts_usec = msg->ts_nsec; |
| 445 | do_div(ts_usec, 1000); | 464 | do_div(ts_usec, 1000); |
| 446 | len = sprintf(user->buf, "%u,%llu,%llu;", | 465 | len = sprintf(user->buf, "%u,%llu,%llu;", |
| 447 | msg->level, user->seq, ts_usec); | 466 | (msg->facility << 3) | msg->level, user->seq, ts_usec); |
| 448 | 467 | ||
| 449 | /* escape non-printable characters */ | 468 | /* escape non-printable characters */ |
| 450 | for (i = 0; i < msg->text_len; i++) { | 469 | for (i = 0; i < msg->text_len; i++) { |
| 451 | unsigned char c = log_text(msg)[i]; | 470 | unsigned char c = log_text(msg)[i]; |
| 452 | 471 | ||
| 453 | if (c < ' ' || c >= 128) | 472 | if (c < ' ' || c >= 127 || c == '\\') |
| 454 | len += sprintf(user->buf + len, "\\x%02x", c); | 473 | len += sprintf(user->buf + len, "\\x%02x", c); |
| 455 | else | 474 | else |
| 456 | user->buf[len++] = c; | 475 | user->buf[len++] = c; |
| @@ -474,7 +493,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, | |||
| 474 | continue; | 493 | continue; |
| 475 | } | 494 | } |
| 476 | 495 | ||
| 477 | if (c < ' ' || c >= 128) { | 496 | if (c < ' ' || c >= 127 || c == '\\') { |
| 478 | len += sprintf(user->buf + len, "\\x%02x", c); | 497 | len += sprintf(user->buf + len, "\\x%02x", c); |
| 479 | continue; | 498 | continue; |
| 480 | } | 499 | } |
| @@ -486,7 +505,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, | |||
| 486 | 505 | ||
| 487 | user->idx = log_next(user->idx); | 506 | user->idx = log_next(user->idx); |
| 488 | user->seq++; | 507 | user->seq++; |
| 489 | raw_spin_unlock(&logbuf_lock); | 508 | raw_spin_unlock_irq(&logbuf_lock); |
| 490 | 509 | ||
| 491 | if (len > count) { | 510 | if (len > count) { |
| 492 | ret = -EINVAL; | 511 | ret = -EINVAL; |
| @@ -513,7 +532,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence) | |||
| 513 | if (offset) | 532 | if (offset) |
| 514 | return -ESPIPE; | 533 | return -ESPIPE; |
| 515 | 534 | ||
| 516 | raw_spin_lock(&logbuf_lock); | 535 | raw_spin_lock_irq(&logbuf_lock); |
| 517 | switch (whence) { | 536 | switch (whence) { |
| 518 | case SEEK_SET: | 537 | case SEEK_SET: |
| 519 | /* the first record */ | 538 | /* the first record */ |
| @@ -537,7 +556,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence) | |||
| 537 | default: | 556 | default: |
| 538 | ret = -EINVAL; | 557 | ret = -EINVAL; |
| 539 | } | 558 | } |
| 540 | raw_spin_unlock(&logbuf_lock); | 559 | raw_spin_unlock_irq(&logbuf_lock); |
| 541 | return ret; | 560 | return ret; |
| 542 | } | 561 | } |
| 543 | 562 | ||
| @@ -551,14 +570,14 @@ static unsigned int devkmsg_poll(struct file *file, poll_table *wait) | |||
| 551 | 570 | ||
| 552 | poll_wait(file, &log_wait, wait); | 571 | poll_wait(file, &log_wait, wait); |
| 553 | 572 | ||
| 554 | raw_spin_lock(&logbuf_lock); | 573 | raw_spin_lock_irq(&logbuf_lock); |
| 555 | if (user->seq < log_next_seq) { | 574 | if (user->seq < log_next_seq) { |
| 556 | /* return error when data has vanished underneath us */ | 575 | /* return error when data has vanished underneath us */ |
| 557 | if (user->seq < log_first_seq) | 576 | if (user->seq < log_first_seq) |
| 558 | ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI; | 577 | ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI; |
| 559 | ret = POLLIN|POLLRDNORM; | 578 | ret = POLLIN|POLLRDNORM; |
| 560 | } | 579 | } |
| 561 | raw_spin_unlock(&logbuf_lock); | 580 | raw_spin_unlock_irq(&logbuf_lock); |
| 562 | 581 | ||
| 563 | return ret; | 582 | return ret; |
| 564 | } | 583 | } |
| @@ -582,10 +601,10 @@ static int devkmsg_open(struct inode *inode, struct file *file) | |||
| 582 | 601 | ||
| 583 | mutex_init(&user->lock); | 602 | mutex_init(&user->lock); |
| 584 | 603 | ||
| 585 | raw_spin_lock(&logbuf_lock); | 604 | raw_spin_lock_irq(&logbuf_lock); |
| 586 | user->idx = log_first_idx; | 605 | user->idx = log_first_idx; |
| 587 | user->seq = log_first_seq; | 606 | user->seq = log_first_seq; |
| 588 | raw_spin_unlock(&logbuf_lock); | 607 | raw_spin_unlock_irq(&logbuf_lock); |
| 589 | 608 | ||
| 590 | file->private_data = user; | 609 | file->private_data = user; |
| 591 | return 0; | 610 | return 0; |
| @@ -785,44 +804,64 @@ static bool printk_time; | |||
| 785 | #endif | 804 | #endif |
| 786 | module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR); | 805 | module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR); |
| 787 | 806 | ||
| 807 | static size_t print_time(u64 ts, char *buf) | ||
| 808 | { | ||
| 809 | unsigned long rem_nsec; | ||
| 810 | |||
| 811 | if (!printk_time) | ||
| 812 | return 0; | ||
| 813 | |||
| 814 | if (!buf) | ||
| 815 | return 15; | ||
| 816 | |||
| 817 | rem_nsec = do_div(ts, 1000000000); | ||
| 818 | return sprintf(buf, "[%5lu.%06lu] ", | ||
| 819 | (unsigned long)ts, rem_nsec / 1000); | ||
| 820 | } | ||
| 821 | |||
| 788 | static size_t print_prefix(const struct log *msg, bool syslog, char *buf) | 822 | static size_t print_prefix(const struct log *msg, bool syslog, char *buf) |
| 789 | { | 823 | { |
| 790 | size_t len = 0; | 824 | size_t len = 0; |
| 825 | unsigned int prefix = (msg->facility << 3) | msg->level; | ||
| 791 | 826 | ||
| 792 | if (syslog) { | 827 | if (syslog) { |
| 793 | if (buf) { | 828 | if (buf) { |
| 794 | len += sprintf(buf, "<%u>", msg->level); | 829 | len += sprintf(buf, "<%u>", prefix); |
| 795 | } else { | 830 | } else { |
| 796 | len += 3; | 831 | len += 3; |
| 797 | if (msg->level > 9) | 832 | if (prefix > 999) |
| 798 | len++; | 833 | len += 3; |
| 799 | if (msg->level > 99) | 834 | else if (prefix > 99) |
| 835 | len += 2; | ||
| 836 | else if (prefix > 9) | ||
| 800 | len++; | 837 | len++; |
| 801 | } | 838 | } |
| 802 | } | 839 | } |
| 803 | 840 | ||
| 804 | if (printk_time) { | 841 | len += print_time(msg->ts_nsec, buf ? buf + len : NULL); |
| 805 | if (buf) { | ||
| 806 | unsigned long long ts = msg->ts_nsec; | ||
| 807 | unsigned long rem_nsec = do_div(ts, 1000000000); | ||
| 808 | |||
| 809 | len += sprintf(buf + len, "[%5lu.%06lu] ", | ||
| 810 | (unsigned long) ts, rem_nsec / 1000); | ||
| 811 | } else { | ||
| 812 | len += 15; | ||
| 813 | } | ||
| 814 | } | ||
| 815 | |||
| 816 | return len; | 842 | return len; |
| 817 | } | 843 | } |
| 818 | 844 | ||
| 819 | static size_t msg_print_text(const struct log *msg, bool syslog, | 845 | static size_t msg_print_text(const struct log *msg, enum log_flags prev, |
| 820 | char *buf, size_t size) | 846 | bool syslog, char *buf, size_t size) |
| 821 | { | 847 | { |
| 822 | const char *text = log_text(msg); | 848 | const char *text = log_text(msg); |
| 823 | size_t text_size = msg->text_len; | 849 | size_t text_size = msg->text_len; |
| 850 | bool prefix = true; | ||
| 851 | bool newline = true; | ||
| 824 | size_t len = 0; | 852 | size_t len = 0; |
| 825 | 853 | ||
| 854 | if ((prev & LOG_CONT) && !(msg->flags & LOG_PREFIX)) | ||
| 855 | prefix = false; | ||
| 856 | |||
| 857 | if (msg->flags & LOG_CONT) { | ||
| 858 | if ((prev & LOG_CONT) && !(prev & LOG_NEWLINE)) | ||
| 859 | prefix = false; | ||
| 860 | |||
| 861 | if (!(msg->flags & LOG_NEWLINE)) | ||
| 862 | newline = false; | ||
| 863 | } | ||
| 864 | |||
| 826 | do { | 865 | do { |
| 827 | const char *next = memchr(text, '\n', text_size); | 866 | const char *next = memchr(text, '\n', text_size); |
| 828 | size_t text_len; | 867 | size_t text_len; |
| @@ -840,16 +879,22 @@ static size_t msg_print_text(const struct log *msg, bool syslog, | |||
| 840 | text_len + 1>= size - len) | 879 | text_len + 1>= size - len) |
| 841 | break; | 880 | break; |
| 842 | 881 | ||
| 843 | len += print_prefix(msg, syslog, buf + len); | 882 | if (prefix) |
| 883 | len += print_prefix(msg, syslog, buf + len); | ||
| 844 | memcpy(buf + len, text, text_len); | 884 | memcpy(buf + len, text, text_len); |
| 845 | len += text_len; | 885 | len += text_len; |
| 846 | buf[len++] = '\n'; | 886 | if (next || newline) |
| 887 | buf[len++] = '\n'; | ||
| 847 | } else { | 888 | } else { |
| 848 | /* SYSLOG_ACTION_* buffer size only calculation */ | 889 | /* SYSLOG_ACTION_* buffer size only calculation */ |
| 849 | len += print_prefix(msg, syslog, NULL); | 890 | if (prefix) |
| 850 | len += text_len + 1; | 891 | len += print_prefix(msg, syslog, NULL); |
| 892 | len += text_len; | ||
| 893 | if (next || newline) | ||
| 894 | len++; | ||
| 851 | } | 895 | } |
| 852 | 896 | ||
| 897 | prefix = true; | ||
| 853 | text = next; | 898 | text = next; |
| 854 | } while (text); | 899 | } while (text); |
| 855 | 900 | ||
| @@ -860,26 +905,60 @@ static int syslog_print(char __user *buf, int size) | |||
| 860 | { | 905 | { |
| 861 | char *text; | 906 | char *text; |
| 862 | struct log *msg; | 907 | struct log *msg; |
| 863 | int len; | 908 | int len = 0; |
| 864 | 909 | ||
| 865 | text = kmalloc(LOG_LINE_MAX, GFP_KERNEL); | 910 | text = kmalloc(LOG_LINE_MAX, GFP_KERNEL); |
| 866 | if (!text) | 911 | if (!text) |
| 867 | return -ENOMEM; | 912 | return -ENOMEM; |
| 868 | 913 | ||
| 869 | raw_spin_lock_irq(&logbuf_lock); | 914 | while (size > 0) { |
| 870 | if (syslog_seq < log_first_seq) { | 915 | size_t n; |
| 871 | /* messages are gone, move to first one */ | 916 | size_t skip; |
| 872 | syslog_seq = log_first_seq; | ||
| 873 | syslog_idx = log_first_idx; | ||
| 874 | } | ||
| 875 | msg = log_from_idx(syslog_idx); | ||
| 876 | len = msg_print_text(msg, true, text, LOG_LINE_MAX); | ||
| 877 | syslog_idx = log_next(syslog_idx); | ||
| 878 | syslog_seq++; | ||
| 879 | raw_spin_unlock_irq(&logbuf_lock); | ||
| 880 | 917 | ||
| 881 | if (len > 0 && copy_to_user(buf, text, len)) | 918 | raw_spin_lock_irq(&logbuf_lock); |
| 882 | len = -EFAULT; | 919 | if (syslog_seq < log_first_seq) { |
| 920 | /* messages are gone, move to first one */ | ||
| 921 | syslog_seq = log_first_seq; | ||
| 922 | syslog_idx = log_first_idx; | ||
| 923 | syslog_prev = 0; | ||
| 924 | syslog_partial = 0; | ||
| 925 | } | ||
| 926 | if (syslog_seq == log_next_seq) { | ||
| 927 | raw_spin_unlock_irq(&logbuf_lock); | ||
| 928 | break; | ||
| 929 | } | ||
| 930 | |||
| 931 | skip = syslog_partial; | ||
| 932 | msg = log_from_idx(syslog_idx); | ||
| 933 | n = msg_print_text(msg, syslog_prev, true, text, LOG_LINE_MAX); | ||
| 934 | if (n - syslog_partial <= size) { | ||
| 935 | /* message fits into buffer, move forward */ | ||
| 936 | syslog_idx = log_next(syslog_idx); | ||
| 937 | syslog_seq++; | ||
| 938 | syslog_prev = msg->flags; | ||
| 939 | n -= syslog_partial; | ||
| 940 | syslog_partial = 0; | ||
| 941 | } else if (!len){ | ||
| 942 | /* partial read(), remember position */ | ||
| 943 | n = size; | ||
| 944 | syslog_partial += n; | ||
| 945 | } else | ||
| 946 | n = 0; | ||
| 947 | raw_spin_unlock_irq(&logbuf_lock); | ||
| 948 | |||
| 949 | if (!n) | ||
| 950 | break; | ||
| 951 | |||
| 952 | if (copy_to_user(buf, text + skip, n)) { | ||
| 953 | if (!len) | ||
| 954 | len = -EFAULT; | ||
| 955 | break; | ||
| 956 | } | ||
| 957 | |||
| 958 | len += n; | ||
| 959 | size -= n; | ||
| 960 | buf += n; | ||
| 961 | } | ||
| 883 | 962 | ||
| 884 | kfree(text); | 963 | kfree(text); |
| 885 | return len; | 964 | return len; |
| @@ -899,6 +978,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear) | |||
| 899 | u64 next_seq; | 978 | u64 next_seq; |
| 900 | u64 seq; | 979 | u64 seq; |
| 901 | u32 idx; | 980 | u32 idx; |
| 981 | enum log_flags prev; | ||
| 902 | 982 | ||
| 903 | if (clear_seq < log_first_seq) { | 983 | if (clear_seq < log_first_seq) { |
| 904 | /* messages are gone, move to first available one */ | 984 | /* messages are gone, move to first available one */ |
| @@ -909,41 +989,47 @@ static int syslog_print_all(char __user *buf, int size, bool clear) | |||
| 909 | /* | 989 | /* |
| 910 | * Find first record that fits, including all following records, | 990 | * Find first record that fits, including all following records, |
| 911 | * into the user-provided buffer for this dump. | 991 | * into the user-provided buffer for this dump. |
| 912 | */ | 992 | */ |
| 913 | seq = clear_seq; | 993 | seq = clear_seq; |
| 914 | idx = clear_idx; | 994 | idx = clear_idx; |
| 995 | prev = 0; | ||
| 915 | while (seq < log_next_seq) { | 996 | while (seq < log_next_seq) { |
| 916 | struct log *msg = log_from_idx(idx); | 997 | struct log *msg = log_from_idx(idx); |
| 917 | 998 | ||
| 918 | len += msg_print_text(msg, true, NULL, 0); | 999 | len += msg_print_text(msg, prev, true, NULL, 0); |
| 919 | idx = log_next(idx); | 1000 | idx = log_next(idx); |
| 920 | seq++; | 1001 | seq++; |
| 921 | } | 1002 | } |
| 1003 | |||
| 1004 | /* move first record forward until length fits into the buffer */ | ||
| 922 | seq = clear_seq; | 1005 | seq = clear_seq; |
| 923 | idx = clear_idx; | 1006 | idx = clear_idx; |
| 1007 | prev = 0; | ||
| 924 | while (len > size && seq < log_next_seq) { | 1008 | while (len > size && seq < log_next_seq) { |
| 925 | struct log *msg = log_from_idx(idx); | 1009 | struct log *msg = log_from_idx(idx); |
| 926 | 1010 | ||
| 927 | len -= msg_print_text(msg, true, NULL, 0); | 1011 | len -= msg_print_text(msg, prev, true, NULL, 0); |
| 928 | idx = log_next(idx); | 1012 | idx = log_next(idx); |
| 929 | seq++; | 1013 | seq++; |
| 930 | } | 1014 | } |
| 931 | 1015 | ||
| 932 | /* last message in this dump */ | 1016 | /* last message fitting into this dump */ |
| 933 | next_seq = log_next_seq; | 1017 | next_seq = log_next_seq; |
| 934 | 1018 | ||
| 935 | len = 0; | 1019 | len = 0; |
| 1020 | prev = 0; | ||
| 936 | while (len >= 0 && seq < next_seq) { | 1021 | while (len >= 0 && seq < next_seq) { |
| 937 | struct log *msg = log_from_idx(idx); | 1022 | struct log *msg = log_from_idx(idx); |
| 938 | int textlen; | 1023 | int textlen; |
| 939 | 1024 | ||
| 940 | textlen = msg_print_text(msg, true, text, LOG_LINE_MAX); | 1025 | textlen = msg_print_text(msg, prev, true, text, LOG_LINE_MAX); |
| 941 | if (textlen < 0) { | 1026 | if (textlen < 0) { |
| 942 | len = textlen; | 1027 | len = textlen; |
| 943 | break; | 1028 | break; |
| 944 | } | 1029 | } |
| 945 | idx = log_next(idx); | 1030 | idx = log_next(idx); |
| 946 | seq++; | 1031 | seq++; |
| 1032 | prev = msg->flags; | ||
| 947 | 1033 | ||
| 948 | raw_spin_unlock_irq(&logbuf_lock); | 1034 | raw_spin_unlock_irq(&logbuf_lock); |
| 949 | if (copy_to_user(buf + len, text, textlen)) | 1035 | if (copy_to_user(buf + len, text, textlen)) |
| @@ -956,6 +1042,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear) | |||
| 956 | /* messages are gone, move to next one */ | 1042 | /* messages are gone, move to next one */ |
| 957 | seq = log_first_seq; | 1043 | seq = log_first_seq; |
| 958 | idx = log_first_idx; | 1044 | idx = log_first_idx; |
| 1045 | prev = 0; | ||
| 959 | } | 1046 | } |
| 960 | } | 1047 | } |
| 961 | } | 1048 | } |
| @@ -1027,6 +1114,7 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) | |||
| 1027 | /* Clear ring buffer */ | 1114 | /* Clear ring buffer */ |
| 1028 | case SYSLOG_ACTION_CLEAR: | 1115 | case SYSLOG_ACTION_CLEAR: |
| 1029 | syslog_print_all(NULL, 0, true); | 1116 | syslog_print_all(NULL, 0, true); |
| 1117 | break; | ||
| 1030 | /* Disable logging to console */ | 1118 | /* Disable logging to console */ |
| 1031 | case SYSLOG_ACTION_CONSOLE_OFF: | 1119 | case SYSLOG_ACTION_CONSOLE_OFF: |
| 1032 | if (saved_console_loglevel == -1) | 1120 | if (saved_console_loglevel == -1) |
| @@ -1059,6 +1147,8 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) | |||
| 1059 | /* messages are gone, move to first one */ | 1147 | /* messages are gone, move to first one */ |
| 1060 | syslog_seq = log_first_seq; | 1148 | syslog_seq = log_first_seq; |
| 1061 | syslog_idx = log_first_idx; | 1149 | syslog_idx = log_first_idx; |
| 1150 | syslog_prev = 0; | ||
| 1151 | syslog_partial = 0; | ||
| 1062 | } | 1152 | } |
| 1063 | if (from_file) { | 1153 | if (from_file) { |
| 1064 | /* | 1154 | /* |
| @@ -1068,19 +1158,20 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) | |||
| 1068 | */ | 1158 | */ |
| 1069 | error = log_next_idx - syslog_idx; | 1159 | error = log_next_idx - syslog_idx; |
| 1070 | } else { | 1160 | } else { |
| 1071 | u64 seq; | 1161 | u64 seq = syslog_seq; |
| 1072 | u32 idx; | 1162 | u32 idx = syslog_idx; |
| 1163 | enum log_flags prev = syslog_prev; | ||
| 1073 | 1164 | ||
| 1074 | error = 0; | 1165 | error = 0; |
| 1075 | seq = syslog_seq; | ||
| 1076 | idx = syslog_idx; | ||
| 1077 | while (seq < log_next_seq) { | 1166 | while (seq < log_next_seq) { |
| 1078 | struct log *msg = log_from_idx(idx); | 1167 | struct log *msg = log_from_idx(idx); |
| 1079 | 1168 | ||
| 1080 | error += msg_print_text(msg, true, NULL, 0); | 1169 | error += msg_print_text(msg, prev, true, NULL, 0); |
| 1081 | idx = log_next(idx); | 1170 | idx = log_next(idx); |
| 1082 | seq++; | 1171 | seq++; |
| 1172 | prev = msg->flags; | ||
| 1083 | } | 1173 | } |
| 1174 | error -= syslog_partial; | ||
| 1084 | } | 1175 | } |
| 1085 | raw_spin_unlock_irq(&logbuf_lock); | 1176 | raw_spin_unlock_irq(&logbuf_lock); |
| 1086 | break; | 1177 | break; |
| @@ -1101,21 +1192,6 @@ SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) | |||
| 1101 | return do_syslog(type, buf, len, SYSLOG_FROM_CALL); | 1192 | return do_syslog(type, buf, len, SYSLOG_FROM_CALL); |
| 1102 | } | 1193 | } |
| 1103 | 1194 | ||
| 1104 | #ifdef CONFIG_KGDB_KDB | ||
| 1105 | /* kdb dmesg command needs access to the syslog buffer. do_syslog() | ||
| 1106 | * uses locks so it cannot be used during debugging. Just tell kdb | ||
| 1107 | * where the start and end of the physical and logical logs are. This | ||
| 1108 | * is equivalent to do_syslog(3). | ||
| 1109 | */ | ||
| 1110 | void kdb_syslog_data(char *syslog_data[4]) | ||
| 1111 | { | ||
| 1112 | syslog_data[0] = log_buf; | ||
| 1113 | syslog_data[1] = log_buf + log_buf_len; | ||
| 1114 | syslog_data[2] = log_buf + log_first_idx; | ||
| 1115 | syslog_data[3] = log_buf + log_next_idx; | ||
| 1116 | } | ||
| 1117 | #endif /* CONFIG_KGDB_KDB */ | ||
| 1118 | |||
| 1119 | static bool __read_mostly ignore_loglevel; | 1195 | static bool __read_mostly ignore_loglevel; |
| 1120 | 1196 | ||
| 1121 | static int __init ignore_loglevel_setup(char *str) | 1197 | static int __init ignore_loglevel_setup(char *str) |
| @@ -1259,22 +1335,98 @@ static inline void printk_delay(void) | |||
| 1259 | } | 1335 | } |
| 1260 | } | 1336 | } |
| 1261 | 1337 | ||
| 1338 | /* | ||
| 1339 | * Continuation lines are buffered, and not committed to the record buffer | ||
| 1340 | * until the line is complete, or a race forces it. The line fragments | ||
| 1341 | * though, are printed immediately to the consoles to ensure everything has | ||
| 1342 | * reached the console in case of a kernel crash. | ||
| 1343 | */ | ||
| 1344 | static struct cont { | ||
| 1345 | char buf[LOG_LINE_MAX]; | ||
| 1346 | size_t len; /* length == 0 means unused buffer */ | ||
| 1347 | size_t cons; /* bytes written to console */ | ||
| 1348 | struct task_struct *owner; /* task of first print*/ | ||
| 1349 | u64 ts_nsec; /* time of first print */ | ||
| 1350 | u8 level; /* log level of first message */ | ||
| 1351 | u8 facility; /* log level of first message */ | ||
| 1352 | bool flushed:1; /* buffer sealed and committed */ | ||
| 1353 | } cont; | ||
| 1354 | |||
| 1355 | static void cont_flush(void) | ||
| 1356 | { | ||
| 1357 | if (cont.flushed) | ||
| 1358 | return; | ||
| 1359 | if (cont.len == 0) | ||
| 1360 | return; | ||
| 1361 | |||
| 1362 | log_store(cont.facility, cont.level, LOG_NOCONS, cont.ts_nsec, | ||
| 1363 | NULL, 0, cont.buf, cont.len); | ||
| 1364 | |||
| 1365 | cont.flushed = true; | ||
| 1366 | } | ||
| 1367 | |||
| 1368 | static bool cont_add(int facility, int level, const char *text, size_t len) | ||
| 1369 | { | ||
| 1370 | if (cont.len && cont.flushed) | ||
| 1371 | return false; | ||
| 1372 | |||
| 1373 | if (cont.len + len > sizeof(cont.buf)) { | ||
| 1374 | cont_flush(); | ||
| 1375 | return false; | ||
| 1376 | } | ||
| 1377 | |||
| 1378 | if (!cont.len) { | ||
| 1379 | cont.facility = facility; | ||
| 1380 | cont.level = level; | ||
| 1381 | cont.owner = current; | ||
| 1382 | cont.ts_nsec = local_clock(); | ||
| 1383 | cont.cons = 0; | ||
| 1384 | cont.flushed = false; | ||
| 1385 | } | ||
| 1386 | |||
| 1387 | memcpy(cont.buf + cont.len, text, len); | ||
| 1388 | cont.len += len; | ||
| 1389 | return true; | ||
| 1390 | } | ||
| 1391 | |||
| 1392 | static size_t cont_print_text(char *text, size_t size) | ||
| 1393 | { | ||
| 1394 | size_t textlen = 0; | ||
| 1395 | size_t len; | ||
| 1396 | |||
| 1397 | if (cont.cons == 0) { | ||
| 1398 | textlen += print_time(cont.ts_nsec, text); | ||
| 1399 | size -= textlen; | ||
| 1400 | } | ||
| 1401 | |||
| 1402 | len = cont.len - cont.cons; | ||
| 1403 | if (len > 0) { | ||
| 1404 | if (len+1 > size) | ||
| 1405 | len = size-1; | ||
| 1406 | memcpy(text + textlen, cont.buf + cont.cons, len); | ||
| 1407 | textlen += len; | ||
| 1408 | cont.cons = cont.len; | ||
| 1409 | } | ||
| 1410 | |||
| 1411 | if (cont.flushed) { | ||
| 1412 | text[textlen++] = '\n'; | ||
| 1413 | /* got everything, release buffer */ | ||
| 1414 | cont.len = 0; | ||
| 1415 | } | ||
| 1416 | return textlen; | ||
| 1417 | } | ||
| 1418 | |||
| 1262 | asmlinkage int vprintk_emit(int facility, int level, | 1419 | asmlinkage int vprintk_emit(int facility, int level, |
| 1263 | const char *dict, size_t dictlen, | 1420 | const char *dict, size_t dictlen, |
| 1264 | const char *fmt, va_list args) | 1421 | const char *fmt, va_list args) |
| 1265 | { | 1422 | { |
| 1266 | static int recursion_bug; | 1423 | static int recursion_bug; |
| 1267 | static char cont_buf[LOG_LINE_MAX]; | ||
| 1268 | static size_t cont_len; | ||
| 1269 | static int cont_level; | ||
| 1270 | static struct task_struct *cont_task; | ||
| 1271 | static char textbuf[LOG_LINE_MAX]; | 1424 | static char textbuf[LOG_LINE_MAX]; |
| 1272 | char *text = textbuf; | 1425 | char *text = textbuf; |
| 1273 | size_t text_len; | 1426 | size_t text_len; |
| 1427 | enum log_flags lflags = 0; | ||
| 1274 | unsigned long flags; | 1428 | unsigned long flags; |
| 1275 | int this_cpu; | 1429 | int this_cpu; |
| 1276 | bool newline = false; | ||
| 1277 | bool prefix = false; | ||
| 1278 | int printed_len = 0; | 1430 | int printed_len = 0; |
| 1279 | 1431 | ||
| 1280 | boot_delay_msec(); | 1432 | boot_delay_msec(); |
| @@ -1313,7 +1465,8 @@ asmlinkage int vprintk_emit(int facility, int level, | |||
| 1313 | recursion_bug = 0; | 1465 | recursion_bug = 0; |
| 1314 | printed_len += strlen(recursion_msg); | 1466 | printed_len += strlen(recursion_msg); |
| 1315 | /* emit KERN_CRIT message */ | 1467 | /* emit KERN_CRIT message */ |
| 1316 | log_store(0, 2, NULL, 0, recursion_msg, printed_len); | 1468 | log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0, |
| 1469 | NULL, 0, recursion_msg, printed_len); | ||
| 1317 | } | 1470 | } |
| 1318 | 1471 | ||
| 1319 | /* | 1472 | /* |
| @@ -1325,7 +1478,7 @@ asmlinkage int vprintk_emit(int facility, int level, | |||
| 1325 | /* mark and strip a trailing newline */ | 1478 | /* mark and strip a trailing newline */ |
| 1326 | if (text_len && text[text_len-1] == '\n') { | 1479 | if (text_len && text[text_len-1] == '\n') { |
| 1327 | text_len--; | 1480 | text_len--; |
| 1328 | newline = true; | 1481 | lflags |= LOG_NEWLINE; |
| 1329 | } | 1482 | } |
| 1330 | 1483 | ||
| 1331 | /* strip syslog prefix and extract log level or control flags */ | 1484 | /* strip syslog prefix and extract log level or control flags */ |
| @@ -1335,7 +1488,7 @@ asmlinkage int vprintk_emit(int facility, int level, | |||
| 1335 | if (level == -1) | 1488 | if (level == -1) |
| 1336 | level = text[1] - '0'; | 1489 | level = text[1] - '0'; |
| 1337 | case 'd': /* KERN_DEFAULT */ | 1490 | case 'd': /* KERN_DEFAULT */ |
| 1338 | prefix = true; | 1491 | lflags |= LOG_PREFIX; |
| 1339 | case 'c': /* KERN_CONT */ | 1492 | case 'c': /* KERN_CONT */ |
| 1340 | text += 3; | 1493 | text += 3; |
| 1341 | text_len -= 3; | 1494 | text_len -= 3; |
| @@ -1345,61 +1498,41 @@ asmlinkage int vprintk_emit(int facility, int level, | |||
| 1345 | if (level == -1) | 1498 | if (level == -1) |
| 1346 | level = default_message_loglevel; | 1499 | level = default_message_loglevel; |
| 1347 | 1500 | ||
| 1348 | if (dict) { | 1501 | if (dict) |
| 1349 | prefix = true; | 1502 | lflags |= LOG_PREFIX|LOG_NEWLINE; |
| 1350 | newline = true; | ||
| 1351 | } | ||
| 1352 | |||
| 1353 | if (!newline) { | ||
| 1354 | if (cont_len && (prefix || cont_task != current)) { | ||
| 1355 | /* | ||
| 1356 | * Flush earlier buffer, which is either from a | ||
| 1357 | * different thread, or when we got a new prefix. | ||
| 1358 | */ | ||
| 1359 | log_store(facility, cont_level, NULL, 0, cont_buf, cont_len); | ||
| 1360 | cont_len = 0; | ||
| 1361 | } | ||
| 1362 | 1503 | ||
| 1363 | if (!cont_len) { | 1504 | if (!(lflags & LOG_NEWLINE)) { |
| 1364 | cont_level = level; | 1505 | /* |
| 1365 | cont_task = current; | 1506 | * Flush the conflicting buffer. An earlier newline was missing, |
| 1366 | } | 1507 | * or another task also prints continuation lines. |
| 1508 | */ | ||
| 1509 | if (cont.len && (lflags & LOG_PREFIX || cont.owner != current)) | ||
| 1510 | cont_flush(); | ||
| 1367 | 1511 | ||
| 1368 | /* buffer or append to earlier buffer from the same thread */ | 1512 | /* buffer line if possible, otherwise store it right away */ |
| 1369 | if (cont_len + text_len > sizeof(cont_buf)) | 1513 | if (!cont_add(facility, level, text, text_len)) |
| 1370 | text_len = sizeof(cont_buf) - cont_len; | 1514 | log_store(facility, level, lflags | LOG_CONT, 0, |
| 1371 | memcpy(cont_buf + cont_len, text, text_len); | 1515 | dict, dictlen, text, text_len); |
| 1372 | cont_len += text_len; | ||
| 1373 | } else { | 1516 | } else { |
| 1374 | if (cont_len && cont_task == current) { | 1517 | bool stored = false; |
| 1375 | if (prefix) { | ||
| 1376 | /* | ||
| 1377 | * New prefix from the same thread; flush. We | ||
| 1378 | * either got no earlier newline, or we race | ||
| 1379 | * with an interrupt. | ||
| 1380 | */ | ||
| 1381 | log_store(facility, cont_level, | ||
| 1382 | NULL, 0, cont_buf, cont_len); | ||
| 1383 | cont_len = 0; | ||
| 1384 | } | ||
| 1385 | 1518 | ||
| 1386 | /* append to the earlier buffer and flush */ | 1519 | /* |
| 1387 | if (cont_len + text_len > sizeof(cont_buf)) | 1520 | * If an earlier newline was missing and it was the same task, |
| 1388 | text_len = sizeof(cont_buf) - cont_len; | 1521 | * either merge it with the current buffer and flush, or if |
| 1389 | memcpy(cont_buf + cont_len, text, text_len); | 1522 | * there was a race with interrupts (prefix == true) then just |
| 1390 | cont_len += text_len; | 1523 | * flush it out and store this line separately. |
| 1391 | log_store(facility, cont_level, | 1524 | */ |
| 1392 | NULL, 0, cont_buf, cont_len); | 1525 | if (cont.len && cont.owner == current) { |
| 1393 | cont_len = 0; | 1526 | if (!(lflags & LOG_PREFIX)) |
| 1394 | cont_task = NULL; | 1527 | stored = cont_add(facility, level, text, text_len); |
| 1395 | printed_len = cont_len; | 1528 | cont_flush(); |
| 1396 | } else { | ||
| 1397 | /* ordinary single and terminated line */ | ||
| 1398 | log_store(facility, level, | ||
| 1399 | dict, dictlen, text, text_len); | ||
| 1400 | printed_len = text_len; | ||
| 1401 | } | 1529 | } |
| 1530 | |||
| 1531 | if (!stored) | ||
| 1532 | log_store(facility, level, lflags, 0, | ||
| 1533 | dict, dictlen, text, text_len); | ||
| 1402 | } | 1534 | } |
| 1535 | printed_len += text_len; | ||
| 1403 | 1536 | ||
| 1404 | /* | 1537 | /* |
| 1405 | * Try to acquire and then immediately release the console semaphore. | 1538 | * Try to acquire and then immediately release the console semaphore. |
| @@ -1486,11 +1619,18 @@ EXPORT_SYMBOL(printk); | |||
| 1486 | #else | 1619 | #else |
| 1487 | 1620 | ||
| 1488 | #define LOG_LINE_MAX 0 | 1621 | #define LOG_LINE_MAX 0 |
| 1622 | static struct cont { | ||
| 1623 | size_t len; | ||
| 1624 | size_t cons; | ||
| 1625 | u8 level; | ||
| 1626 | bool flushed:1; | ||
| 1627 | } cont; | ||
| 1489 | static struct log *log_from_idx(u32 idx) { return NULL; } | 1628 | static struct log *log_from_idx(u32 idx) { return NULL; } |
| 1490 | static u32 log_next(u32 idx) { return 0; } | 1629 | static u32 log_next(u32 idx) { return 0; } |
| 1491 | static void call_console_drivers(int level, const char *text, size_t len) {} | 1630 | static void call_console_drivers(int level, const char *text, size_t len) {} |
| 1492 | static size_t msg_print_text(const struct log *msg, bool syslog, | 1631 | static size_t msg_print_text(const struct log *msg, enum log_flags prev, |
| 1493 | char *buf, size_t size) { return 0; } | 1632 | bool syslog, char *buf, size_t size) { return 0; } |
| 1633 | static size_t cont_print_text(char *text, size_t size) { return 0; } | ||
| 1494 | 1634 | ||
| 1495 | #endif /* CONFIG_PRINTK */ | 1635 | #endif /* CONFIG_PRINTK */ |
| 1496 | 1636 | ||
| @@ -1765,6 +1905,7 @@ void wake_up_klogd(void) | |||
| 1765 | /* the next printk record to write to the console */ | 1905 | /* the next printk record to write to the console */ |
| 1766 | static u64 console_seq; | 1906 | static u64 console_seq; |
| 1767 | static u32 console_idx; | 1907 | static u32 console_idx; |
| 1908 | static enum log_flags console_prev; | ||
| 1768 | 1909 | ||
| 1769 | /** | 1910 | /** |
| 1770 | * console_unlock - unlock the console system | 1911 | * console_unlock - unlock the console system |
| @@ -1782,6 +1923,7 @@ static u32 console_idx; | |||
| 1782 | */ | 1923 | */ |
| 1783 | void console_unlock(void) | 1924 | void console_unlock(void) |
| 1784 | { | 1925 | { |
| 1926 | static char text[LOG_LINE_MAX]; | ||
| 1785 | static u64 seen_seq; | 1927 | static u64 seen_seq; |
| 1786 | unsigned long flags; | 1928 | unsigned long flags; |
| 1787 | bool wake_klogd = false; | 1929 | bool wake_klogd = false; |
| @@ -1794,10 +1936,23 @@ void console_unlock(void) | |||
| 1794 | 1936 | ||
| 1795 | console_may_schedule = 0; | 1937 | console_may_schedule = 0; |
| 1796 | 1938 | ||
| 1939 | /* flush buffered message fragment immediately to console */ | ||
| 1940 | raw_spin_lock_irqsave(&logbuf_lock, flags); | ||
| 1941 | if (cont.len && (cont.cons < cont.len || cont.flushed)) { | ||
| 1942 | size_t len; | ||
| 1943 | |||
| 1944 | len = cont_print_text(text, sizeof(text)); | ||
| 1945 | raw_spin_unlock(&logbuf_lock); | ||
| 1946 | stop_critical_timings(); | ||
| 1947 | call_console_drivers(cont.level, text, len); | ||
| 1948 | start_critical_timings(); | ||
| 1949 | local_irq_restore(flags); | ||
| 1950 | } else | ||
| 1951 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | ||
| 1952 | |||
| 1797 | again: | 1953 | again: |
| 1798 | for (;;) { | 1954 | for (;;) { |
| 1799 | struct log *msg; | 1955 | struct log *msg; |
| 1800 | static char text[LOG_LINE_MAX]; | ||
| 1801 | size_t len; | 1956 | size_t len; |
| 1802 | int level; | 1957 | int level; |
| 1803 | 1958 | ||
| @@ -1811,18 +1966,35 @@ again: | |||
| 1811 | /* messages are gone, move to first one */ | 1966 | /* messages are gone, move to first one */ |
| 1812 | console_seq = log_first_seq; | 1967 | console_seq = log_first_seq; |
| 1813 | console_idx = log_first_idx; | 1968 | console_idx = log_first_idx; |
| 1969 | console_prev = 0; | ||
| 1814 | } | 1970 | } |
| 1815 | 1971 | skip: | |
| 1816 | if (console_seq == log_next_seq) | 1972 | if (console_seq == log_next_seq) |
| 1817 | break; | 1973 | break; |
| 1818 | 1974 | ||
| 1819 | msg = log_from_idx(console_idx); | 1975 | msg = log_from_idx(console_idx); |
| 1820 | level = msg->level & 7; | 1976 | if (msg->flags & LOG_NOCONS) { |
| 1821 | 1977 | /* | |
| 1822 | len = msg_print_text(msg, false, text, sizeof(text)); | 1978 | * Skip record we have buffered and already printed |
| 1979 | * directly to the console when we received it. | ||
| 1980 | */ | ||
| 1981 | console_idx = log_next(console_idx); | ||
| 1982 | console_seq++; | ||
| 1983 | /* | ||
| 1984 | * We will get here again when we register a new | ||
| 1985 | * CON_PRINTBUFFER console. Clear the flag so we | ||
| 1986 | * will properly dump everything later. | ||
| 1987 | */ | ||
| 1988 | msg->flags &= ~LOG_NOCONS; | ||
| 1989 | goto skip; | ||
| 1990 | } | ||
| 1823 | 1991 | ||
| 1992 | level = msg->level; | ||
| 1993 | len = msg_print_text(msg, console_prev, false, | ||
| 1994 | text, sizeof(text)); | ||
| 1824 | console_idx = log_next(console_idx); | 1995 | console_idx = log_next(console_idx); |
| 1825 | console_seq++; | 1996 | console_seq++; |
| 1997 | console_prev = msg->flags; | ||
| 1826 | raw_spin_unlock(&logbuf_lock); | 1998 | raw_spin_unlock(&logbuf_lock); |
| 1827 | 1999 | ||
| 1828 | stop_critical_timings(); /* don't trace print latency */ | 2000 | stop_critical_timings(); /* don't trace print latency */ |
| @@ -2085,6 +2257,7 @@ void register_console(struct console *newcon) | |||
| 2085 | raw_spin_lock_irqsave(&logbuf_lock, flags); | 2257 | raw_spin_lock_irqsave(&logbuf_lock, flags); |
| 2086 | console_seq = syslog_seq; | 2258 | console_seq = syslog_seq; |
| 2087 | console_idx = syslog_idx; | 2259 | console_idx = syslog_idx; |
| 2260 | console_prev = syslog_prev; | ||
| 2088 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | 2261 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); |
| 2089 | /* | 2262 | /* |
| 2090 | * We're about to replay the log buffer. Only do this to the | 2263 | * We're about to replay the log buffer. Only do this to the |
| @@ -2300,48 +2473,256 @@ module_param_named(always_kmsg_dump, always_kmsg_dump, bool, S_IRUGO | S_IWUSR); | |||
| 2300 | * kmsg_dump - dump kernel log to kernel message dumpers. | 2473 | * kmsg_dump - dump kernel log to kernel message dumpers. |
| 2301 | * @reason: the reason (oops, panic etc) for dumping | 2474 | * @reason: the reason (oops, panic etc) for dumping |
| 2302 | * | 2475 | * |
| 2303 | * Iterate through each of the dump devices and call the oops/panic | 2476 | * Call each of the registered dumper's dump() callback, which can |
| 2304 | * callbacks with the log buffer. | 2477 | * retrieve the kmsg records with kmsg_dump_get_line() or |
| 2478 | * kmsg_dump_get_buffer(). | ||
| 2305 | */ | 2479 | */ |
| 2306 | void kmsg_dump(enum kmsg_dump_reason reason) | 2480 | void kmsg_dump(enum kmsg_dump_reason reason) |
| 2307 | { | 2481 | { |
| 2308 | u64 idx; | ||
| 2309 | struct kmsg_dumper *dumper; | 2482 | struct kmsg_dumper *dumper; |
| 2310 | const char *s1, *s2; | ||
| 2311 | unsigned long l1, l2; | ||
| 2312 | unsigned long flags; | 2483 | unsigned long flags; |
| 2313 | 2484 | ||
| 2314 | if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump) | 2485 | if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump) |
| 2315 | return; | 2486 | return; |
| 2316 | 2487 | ||
| 2317 | /* Theoretically, the log could move on after we do this, but | 2488 | rcu_read_lock(); |
| 2318 | there's not a lot we can do about that. The new messages | 2489 | list_for_each_entry_rcu(dumper, &dump_list, list) { |
| 2319 | will overwrite the start of what we dump. */ | 2490 | if (dumper->max_reason && reason > dumper->max_reason) |
| 2491 | continue; | ||
| 2492 | |||
| 2493 | /* initialize iterator with data about the stored records */ | ||
| 2494 | dumper->active = true; | ||
| 2495 | |||
| 2496 | raw_spin_lock_irqsave(&logbuf_lock, flags); | ||
| 2497 | dumper->cur_seq = clear_seq; | ||
| 2498 | dumper->cur_idx = clear_idx; | ||
| 2499 | dumper->next_seq = log_next_seq; | ||
| 2500 | dumper->next_idx = log_next_idx; | ||
| 2501 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | ||
| 2502 | |||
| 2503 | /* invoke dumper which will iterate over records */ | ||
| 2504 | dumper->dump(dumper, reason); | ||
| 2505 | |||
| 2506 | /* reset iterator */ | ||
| 2507 | dumper->active = false; | ||
| 2508 | } | ||
| 2509 | rcu_read_unlock(); | ||
| 2510 | } | ||
| 2511 | |||
| 2512 | /** | ||
| 2513 | * kmsg_dump_get_line_nolock - retrieve one kmsg log line (unlocked version) | ||
| 2514 | * @dumper: registered kmsg dumper | ||
| 2515 | * @syslog: include the "<4>" prefixes | ||
| 2516 | * @line: buffer to copy the line to | ||
| 2517 | * @size: maximum size of the buffer | ||
| 2518 | * @len: length of line placed into buffer | ||
| 2519 | * | ||
| 2520 | * Start at the beginning of the kmsg buffer, with the oldest kmsg | ||
| 2521 | * record, and copy one record into the provided buffer. | ||
| 2522 | * | ||
| 2523 | * Consecutive calls will return the next available record moving | ||
| 2524 | * towards the end of the buffer with the youngest messages. | ||
| 2525 | * | ||
| 2526 | * A return value of FALSE indicates that there are no more records to | ||
| 2527 | * read. | ||
| 2528 | * | ||
| 2529 | * The function is similar to kmsg_dump_get_line(), but grabs no locks. | ||
| 2530 | */ | ||
| 2531 | bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog, | ||
| 2532 | char *line, size_t size, size_t *len) | ||
| 2533 | { | ||
| 2534 | struct log *msg; | ||
| 2535 | size_t l = 0; | ||
| 2536 | bool ret = false; | ||
| 2537 | |||
| 2538 | if (!dumper->active) | ||
| 2539 | goto out; | ||
| 2540 | |||
| 2541 | if (dumper->cur_seq < log_first_seq) { | ||
| 2542 | /* messages are gone, move to first available one */ | ||
| 2543 | dumper->cur_seq = log_first_seq; | ||
| 2544 | dumper->cur_idx = log_first_idx; | ||
| 2545 | } | ||
| 2546 | |||
| 2547 | /* last entry */ | ||
| 2548 | if (dumper->cur_seq >= log_next_seq) | ||
| 2549 | goto out; | ||
| 2550 | |||
| 2551 | msg = log_from_idx(dumper->cur_idx); | ||
| 2552 | l = msg_print_text(msg, 0, syslog, line, size); | ||
| 2553 | |||
| 2554 | dumper->cur_idx = log_next(dumper->cur_idx); | ||
| 2555 | dumper->cur_seq++; | ||
| 2556 | ret = true; | ||
| 2557 | out: | ||
| 2558 | if (len) | ||
| 2559 | *len = l; | ||
| 2560 | return ret; | ||
| 2561 | } | ||
| 2562 | |||
| 2563 | /** | ||
| 2564 | * kmsg_dump_get_line - retrieve one kmsg log line | ||
| 2565 | * @dumper: registered kmsg dumper | ||
| 2566 | * @syslog: include the "<4>" prefixes | ||
| 2567 | * @line: buffer to copy the line to | ||
| 2568 | * @size: maximum size of the buffer | ||
| 2569 | * @len: length of line placed into buffer | ||
| 2570 | * | ||
| 2571 | * Start at the beginning of the kmsg buffer, with the oldest kmsg | ||
| 2572 | * record, and copy one record into the provided buffer. | ||
| 2573 | * | ||
| 2574 | * Consecutive calls will return the next available record moving | ||
| 2575 | * towards the end of the buffer with the youngest messages. | ||
| 2576 | * | ||
| 2577 | * A return value of FALSE indicates that there are no more records to | ||
| 2578 | * read. | ||
| 2579 | */ | ||
| 2580 | bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, | ||
| 2581 | char *line, size_t size, size_t *len) | ||
| 2582 | { | ||
| 2583 | unsigned long flags; | ||
| 2584 | bool ret; | ||
| 2585 | |||
| 2586 | raw_spin_lock_irqsave(&logbuf_lock, flags); | ||
| 2587 | ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len); | ||
| 2588 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | ||
| 2589 | |||
| 2590 | return ret; | ||
| 2591 | } | ||
| 2592 | EXPORT_SYMBOL_GPL(kmsg_dump_get_line); | ||
| 2593 | |||
| 2594 | /** | ||
| 2595 | * kmsg_dump_get_buffer - copy kmsg log lines | ||
| 2596 | * @dumper: registered kmsg dumper | ||
| 2597 | * @syslog: include the "<4>" prefixes | ||
| 2598 | * @buf: buffer to copy the line to | ||
| 2599 | * @size: maximum size of the buffer | ||
| 2600 | * @len: length of line placed into buffer | ||
| 2601 | * | ||
| 2602 | * Start at the end of the kmsg buffer and fill the provided buffer | ||
| 2603 | * with as many of the the *youngest* kmsg records that fit into it. | ||
| 2604 | * If the buffer is large enough, all available kmsg records will be | ||
| 2605 | * copied with a single call. | ||
| 2606 | * | ||
| 2607 | * Consecutive calls will fill the buffer with the next block of | ||
| 2608 | * available older records, not including the earlier retrieved ones. | ||
| 2609 | * | ||
| 2610 | * A return value of FALSE indicates that there are no more records to | ||
| 2611 | * read. | ||
| 2612 | */ | ||
| 2613 | bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, | ||
| 2614 | char *buf, size_t size, size_t *len) | ||
| 2615 | { | ||
| 2616 | unsigned long flags; | ||
| 2617 | u64 seq; | ||
| 2618 | u32 idx; | ||
| 2619 | u64 next_seq; | ||
| 2620 | u32 next_idx; | ||
| 2621 | enum log_flags prev; | ||
| 2622 | size_t l = 0; | ||
| 2623 | bool ret = false; | ||
| 2624 | |||
| 2625 | if (!dumper->active) | ||
| 2626 | goto out; | ||
| 2320 | 2627 | ||
| 2321 | raw_spin_lock_irqsave(&logbuf_lock, flags); | 2628 | raw_spin_lock_irqsave(&logbuf_lock, flags); |
| 2322 | if (syslog_seq < log_first_seq) | 2629 | if (dumper->cur_seq < log_first_seq) { |
| 2323 | idx = syslog_idx; | 2630 | /* messages are gone, move to first available one */ |
| 2324 | else | 2631 | dumper->cur_seq = log_first_seq; |
| 2325 | idx = log_first_idx; | 2632 | dumper->cur_idx = log_first_idx; |
| 2633 | } | ||
| 2634 | |||
| 2635 | /* last entry */ | ||
| 2636 | if (dumper->cur_seq >= dumper->next_seq) { | ||
| 2637 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | ||
| 2638 | goto out; | ||
| 2639 | } | ||
| 2326 | 2640 | ||
| 2327 | if (idx > log_next_idx) { | 2641 | /* calculate length of entire buffer */ |
| 2328 | s1 = log_buf; | 2642 | seq = dumper->cur_seq; |
| 2329 | l1 = log_next_idx; | 2643 | idx = dumper->cur_idx; |
| 2644 | prev = 0; | ||
| 2645 | while (seq < dumper->next_seq) { | ||
| 2646 | struct log *msg = log_from_idx(idx); | ||
| 2647 | |||
| 2648 | l += msg_print_text(msg, prev, true, NULL, 0); | ||
| 2649 | idx = log_next(idx); | ||
| 2650 | seq++; | ||
| 2651 | prev = msg->flags; | ||
| 2652 | } | ||
| 2330 | 2653 | ||
| 2331 | s2 = log_buf + idx; | 2654 | /* move first record forward until length fits into the buffer */ |
| 2332 | l2 = log_buf_len - idx; | 2655 | seq = dumper->cur_seq; |
| 2333 | } else { | 2656 | idx = dumper->cur_idx; |
| 2334 | s1 = ""; | 2657 | prev = 0; |
| 2335 | l1 = 0; | 2658 | while (l > size && seq < dumper->next_seq) { |
| 2659 | struct log *msg = log_from_idx(idx); | ||
| 2660 | |||
| 2661 | l -= msg_print_text(msg, prev, true, NULL, 0); | ||
| 2662 | idx = log_next(idx); | ||
| 2663 | seq++; | ||
| 2664 | prev = msg->flags; | ||
| 2665 | } | ||
| 2666 | |||
| 2667 | /* last message in next interation */ | ||
| 2668 | next_seq = seq; | ||
| 2669 | next_idx = idx; | ||
| 2670 | |||
| 2671 | l = 0; | ||
| 2672 | prev = 0; | ||
| 2673 | while (seq < dumper->next_seq) { | ||
| 2674 | struct log *msg = log_from_idx(idx); | ||
| 2336 | 2675 | ||
| 2337 | s2 = log_buf + idx; | 2676 | l += msg_print_text(msg, prev, syslog, buf + l, size - l); |
| 2338 | l2 = log_next_idx - idx; | 2677 | idx = log_next(idx); |
| 2678 | seq++; | ||
| 2679 | prev = msg->flags; | ||
| 2339 | } | 2680 | } |
| 2681 | |||
| 2682 | dumper->next_seq = next_seq; | ||
| 2683 | dumper->next_idx = next_idx; | ||
| 2684 | ret = true; | ||
| 2340 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | 2685 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); |
| 2686 | out: | ||
| 2687 | if (len) | ||
| 2688 | *len = l; | ||
| 2689 | return ret; | ||
| 2690 | } | ||
| 2691 | EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer); | ||
| 2341 | 2692 | ||
| 2342 | rcu_read_lock(); | 2693 | /** |
| 2343 | list_for_each_entry_rcu(dumper, &dump_list, list) | 2694 | * kmsg_dump_rewind_nolock - reset the interator (unlocked version) |
| 2344 | dumper->dump(dumper, reason, s1, l1, s2, l2); | 2695 | * @dumper: registered kmsg dumper |
| 2345 | rcu_read_unlock(); | 2696 | * |
| 2697 | * Reset the dumper's iterator so that kmsg_dump_get_line() and | ||
| 2698 | * kmsg_dump_get_buffer() can be called again and used multiple | ||
| 2699 | * times within the same dumper.dump() callback. | ||
| 2700 | * | ||
| 2701 | * The function is similar to kmsg_dump_rewind(), but grabs no locks. | ||
| 2702 | */ | ||
| 2703 | void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper) | ||
| 2704 | { | ||
| 2705 | dumper->cur_seq = clear_seq; | ||
| 2706 | dumper->cur_idx = clear_idx; | ||
| 2707 | dumper->next_seq = log_next_seq; | ||
| 2708 | dumper->next_idx = log_next_idx; | ||
| 2709 | } | ||
| 2710 | |||
| 2711 | /** | ||
| 2712 | * kmsg_dump_rewind - reset the interator | ||
| 2713 | * @dumper: registered kmsg dumper | ||
| 2714 | * | ||
| 2715 | * Reset the dumper's iterator so that kmsg_dump_get_line() and | ||
| 2716 | * kmsg_dump_get_buffer() can be called again and used multiple | ||
| 2717 | * times within the same dumper.dump() callback. | ||
| 2718 | */ | ||
| 2719 | void kmsg_dump_rewind(struct kmsg_dumper *dumper) | ||
| 2720 | { | ||
| 2721 | unsigned long flags; | ||
| 2722 | |||
| 2723 | raw_spin_lock_irqsave(&logbuf_lock, flags); | ||
| 2724 | kmsg_dump_rewind_nolock(dumper); | ||
| 2725 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | ||
| 2346 | } | 2726 | } |
| 2727 | EXPORT_SYMBOL_GPL(kmsg_dump_rewind); | ||
| 2347 | #endif | 2728 | #endif |
