diff options
Diffstat (limited to 'kernel/printk.c')
-rw-r--r-- | kernel/printk.c | 285 |
1 files changed, 181 insertions, 104 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index dba18211685e..ac4bc9e79465 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -194,8 +194,10 @@ static int console_may_schedule; | |||
194 | */ | 194 | */ |
195 | 195 | ||
196 | enum log_flags { | 196 | enum log_flags { |
197 | LOG_DEFAULT = 0, | 197 | LOG_NOCONS = 1, /* already flushed, do not print to console */ |
198 | 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 */ | ||
199 | }; | 201 | }; |
200 | 202 | ||
201 | struct log { | 203 | struct log { |
@@ -217,6 +219,8 @@ static DEFINE_RAW_SPINLOCK(logbuf_lock); | |||
217 | /* 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 */ |
218 | static u64 syslog_seq; | 220 | static u64 syslog_seq; |
219 | static u32 syslog_idx; | 221 | static u32 syslog_idx; |
222 | static enum log_flags syslog_prev; | ||
223 | static size_t syslog_partial; | ||
220 | 224 | ||
221 | /* 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 */ |
222 | static u64 log_first_seq; | 226 | static u64 log_first_seq; |
@@ -430,20 +434,20 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, | |||
430 | ret = mutex_lock_interruptible(&user->lock); | 434 | ret = mutex_lock_interruptible(&user->lock); |
431 | if (ret) | 435 | if (ret) |
432 | return ret; | 436 | return ret; |
433 | raw_spin_lock(&logbuf_lock); | 437 | raw_spin_lock_irq(&logbuf_lock); |
434 | while (user->seq == log_next_seq) { | 438 | while (user->seq == log_next_seq) { |
435 | if (file->f_flags & O_NONBLOCK) { | 439 | if (file->f_flags & O_NONBLOCK) { |
436 | ret = -EAGAIN; | 440 | ret = -EAGAIN; |
437 | raw_spin_unlock(&logbuf_lock); | 441 | raw_spin_unlock_irq(&logbuf_lock); |
438 | goto out; | 442 | goto out; |
439 | } | 443 | } |
440 | 444 | ||
441 | raw_spin_unlock(&logbuf_lock); | 445 | raw_spin_unlock_irq(&logbuf_lock); |
442 | ret = wait_event_interruptible(log_wait, | 446 | ret = wait_event_interruptible(log_wait, |
443 | user->seq != log_next_seq); | 447 | user->seq != log_next_seq); |
444 | if (ret) | 448 | if (ret) |
445 | goto out; | 449 | goto out; |
446 | raw_spin_lock(&logbuf_lock); | 450 | raw_spin_lock_irq(&logbuf_lock); |
447 | } | 451 | } |
448 | 452 | ||
449 | if (user->seq < log_first_seq) { | 453 | if (user->seq < log_first_seq) { |
@@ -451,7 +455,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, | |||
451 | user->idx = log_first_idx; | 455 | user->idx = log_first_idx; |
452 | user->seq = log_first_seq; | 456 | user->seq = log_first_seq; |
453 | ret = -EPIPE; | 457 | ret = -EPIPE; |
454 | raw_spin_unlock(&logbuf_lock); | 458 | raw_spin_unlock_irq(&logbuf_lock); |
455 | goto out; | 459 | goto out; |
456 | } | 460 | } |
457 | 461 | ||
@@ -465,7 +469,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, | |||
465 | for (i = 0; i < msg->text_len; i++) { | 469 | for (i = 0; i < msg->text_len; i++) { |
466 | unsigned char c = log_text(msg)[i]; | 470 | unsigned char c = log_text(msg)[i]; |
467 | 471 | ||
468 | if (c < ' ' || c >= 128) | 472 | if (c < ' ' || c >= 127 || c == '\\') |
469 | len += sprintf(user->buf + len, "\\x%02x", c); | 473 | len += sprintf(user->buf + len, "\\x%02x", c); |
470 | else | 474 | else |
471 | user->buf[len++] = c; | 475 | user->buf[len++] = c; |
@@ -489,7 +493,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, | |||
489 | continue; | 493 | continue; |
490 | } | 494 | } |
491 | 495 | ||
492 | if (c < ' ' || c >= 128) { | 496 | if (c < ' ' || c >= 127 || c == '\\') { |
493 | len += sprintf(user->buf + len, "\\x%02x", c); | 497 | len += sprintf(user->buf + len, "\\x%02x", c); |
494 | continue; | 498 | continue; |
495 | } | 499 | } |
@@ -501,7 +505,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, | |||
501 | 505 | ||
502 | user->idx = log_next(user->idx); | 506 | user->idx = log_next(user->idx); |
503 | user->seq++; | 507 | user->seq++; |
504 | raw_spin_unlock(&logbuf_lock); | 508 | raw_spin_unlock_irq(&logbuf_lock); |
505 | 509 | ||
506 | if (len > count) { | 510 | if (len > count) { |
507 | ret = -EINVAL; | 511 | ret = -EINVAL; |
@@ -528,7 +532,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence) | |||
528 | if (offset) | 532 | if (offset) |
529 | return -ESPIPE; | 533 | return -ESPIPE; |
530 | 534 | ||
531 | raw_spin_lock(&logbuf_lock); | 535 | raw_spin_lock_irq(&logbuf_lock); |
532 | switch (whence) { | 536 | switch (whence) { |
533 | case SEEK_SET: | 537 | case SEEK_SET: |
534 | /* the first record */ | 538 | /* the first record */ |
@@ -552,7 +556,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence) | |||
552 | default: | 556 | default: |
553 | ret = -EINVAL; | 557 | ret = -EINVAL; |
554 | } | 558 | } |
555 | raw_spin_unlock(&logbuf_lock); | 559 | raw_spin_unlock_irq(&logbuf_lock); |
556 | return ret; | 560 | return ret; |
557 | } | 561 | } |
558 | 562 | ||
@@ -566,14 +570,14 @@ static unsigned int devkmsg_poll(struct file *file, poll_table *wait) | |||
566 | 570 | ||
567 | poll_wait(file, &log_wait, wait); | 571 | poll_wait(file, &log_wait, wait); |
568 | 572 | ||
569 | raw_spin_lock(&logbuf_lock); | 573 | raw_spin_lock_irq(&logbuf_lock); |
570 | if (user->seq < log_next_seq) { | 574 | if (user->seq < log_next_seq) { |
571 | /* return error when data has vanished underneath us */ | 575 | /* return error when data has vanished underneath us */ |
572 | if (user->seq < log_first_seq) | 576 | if (user->seq < log_first_seq) |
573 | ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI; | 577 | ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI; |
574 | ret = POLLIN|POLLRDNORM; | 578 | ret = POLLIN|POLLRDNORM; |
575 | } | 579 | } |
576 | raw_spin_unlock(&logbuf_lock); | 580 | raw_spin_unlock_irq(&logbuf_lock); |
577 | 581 | ||
578 | return ret; | 582 | return ret; |
579 | } | 583 | } |
@@ -597,10 +601,10 @@ static int devkmsg_open(struct inode *inode, struct file *file) | |||
597 | 601 | ||
598 | mutex_init(&user->lock); | 602 | mutex_init(&user->lock); |
599 | 603 | ||
600 | raw_spin_lock(&logbuf_lock); | 604 | raw_spin_lock_irq(&logbuf_lock); |
601 | user->idx = log_first_idx; | 605 | user->idx = log_first_idx; |
602 | user->seq = log_first_seq; | 606 | user->seq = log_first_seq; |
603 | raw_spin_unlock(&logbuf_lock); | 607 | raw_spin_unlock_irq(&logbuf_lock); |
604 | 608 | ||
605 | file->private_data = user; | 609 | file->private_data = user; |
606 | return 0; | 610 | return 0; |
@@ -818,15 +822,18 @@ static size_t print_time(u64 ts, char *buf) | |||
818 | 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) |
819 | { | 823 | { |
820 | size_t len = 0; | 824 | size_t len = 0; |
825 | unsigned int prefix = (msg->facility << 3) | msg->level; | ||
821 | 826 | ||
822 | if (syslog) { | 827 | if (syslog) { |
823 | if (buf) { | 828 | if (buf) { |
824 | len += sprintf(buf, "<%u>", msg->level); | 829 | len += sprintf(buf, "<%u>", prefix); |
825 | } else { | 830 | } else { |
826 | len += 3; | 831 | len += 3; |
827 | if (msg->level > 9) | 832 | if (prefix > 999) |
828 | len++; | 833 | len += 3; |
829 | if (msg->level > 99) | 834 | else if (prefix > 99) |
835 | len += 2; | ||
836 | else if (prefix > 9) | ||
830 | len++; | 837 | len++; |
831 | } | 838 | } |
832 | } | 839 | } |
@@ -835,13 +842,26 @@ static size_t print_prefix(const struct log *msg, bool syslog, char *buf) | |||
835 | return len; | 842 | return len; |
836 | } | 843 | } |
837 | 844 | ||
838 | 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, |
839 | char *buf, size_t size) | 846 | bool syslog, char *buf, size_t size) |
840 | { | 847 | { |
841 | const char *text = log_text(msg); | 848 | const char *text = log_text(msg); |
842 | size_t text_size = msg->text_len; | 849 | size_t text_size = msg->text_len; |
850 | bool prefix = true; | ||
851 | bool newline = true; | ||
843 | size_t len = 0; | 852 | size_t len = 0; |
844 | 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 | |||
845 | do { | 865 | do { |
846 | const char *next = memchr(text, '\n', text_size); | 866 | const char *next = memchr(text, '\n', text_size); |
847 | size_t text_len; | 867 | size_t text_len; |
@@ -859,16 +879,22 @@ static size_t msg_print_text(const struct log *msg, bool syslog, | |||
859 | text_len + 1>= size - len) | 879 | text_len + 1>= size - len) |
860 | break; | 880 | break; |
861 | 881 | ||
862 | len += print_prefix(msg, syslog, buf + len); | 882 | if (prefix) |
883 | len += print_prefix(msg, syslog, buf + len); | ||
863 | memcpy(buf + len, text, text_len); | 884 | memcpy(buf + len, text, text_len); |
864 | len += text_len; | 885 | len += text_len; |
865 | buf[len++] = '\n'; | 886 | if (next || newline) |
887 | buf[len++] = '\n'; | ||
866 | } else { | 888 | } else { |
867 | /* SYSLOG_ACTION_* buffer size only calculation */ | 889 | /* SYSLOG_ACTION_* buffer size only calculation */ |
868 | len += print_prefix(msg, syslog, NULL); | 890 | if (prefix) |
869 | len += text_len + 1; | 891 | len += print_prefix(msg, syslog, NULL); |
892 | len += text_len; | ||
893 | if (next || newline) | ||
894 | len++; | ||
870 | } | 895 | } |
871 | 896 | ||
897 | prefix = true; | ||
872 | text = next; | 898 | text = next; |
873 | } while (text); | 899 | } while (text); |
874 | 900 | ||
@@ -887,22 +913,35 @@ static int syslog_print(char __user *buf, int size) | |||
887 | 913 | ||
888 | while (size > 0) { | 914 | while (size > 0) { |
889 | size_t n; | 915 | size_t n; |
916 | size_t skip; | ||
890 | 917 | ||
891 | raw_spin_lock_irq(&logbuf_lock); | 918 | raw_spin_lock_irq(&logbuf_lock); |
892 | if (syslog_seq < log_first_seq) { | 919 | if (syslog_seq < log_first_seq) { |
893 | /* messages are gone, move to first one */ | 920 | /* messages are gone, move to first one */ |
894 | syslog_seq = log_first_seq; | 921 | syslog_seq = log_first_seq; |
895 | syslog_idx = log_first_idx; | 922 | syslog_idx = log_first_idx; |
923 | syslog_prev = 0; | ||
924 | syslog_partial = 0; | ||
896 | } | 925 | } |
897 | if (syslog_seq == log_next_seq) { | 926 | if (syslog_seq == log_next_seq) { |
898 | raw_spin_unlock_irq(&logbuf_lock); | 927 | raw_spin_unlock_irq(&logbuf_lock); |
899 | break; | 928 | break; |
900 | } | 929 | } |
930 | |||
931 | skip = syslog_partial; | ||
901 | msg = log_from_idx(syslog_idx); | 932 | msg = log_from_idx(syslog_idx); |
902 | n = msg_print_text(msg, true, text, LOG_LINE_MAX); | 933 | n = msg_print_text(msg, syslog_prev, true, text, LOG_LINE_MAX); |
903 | if (n <= size) { | 934 | if (n - syslog_partial <= size) { |
935 | /* message fits into buffer, move forward */ | ||
904 | syslog_idx = log_next(syslog_idx); | 936 | syslog_idx = log_next(syslog_idx); |
905 | syslog_seq++; | 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; | ||
906 | } else | 945 | } else |
907 | n = 0; | 946 | n = 0; |
908 | raw_spin_unlock_irq(&logbuf_lock); | 947 | raw_spin_unlock_irq(&logbuf_lock); |
@@ -910,17 +949,15 @@ static int syslog_print(char __user *buf, int size) | |||
910 | if (!n) | 949 | if (!n) |
911 | break; | 950 | break; |
912 | 951 | ||
913 | len += n; | 952 | if (copy_to_user(buf, text + skip, n)) { |
914 | size -= n; | ||
915 | buf += n; | ||
916 | n = copy_to_user(buf - n, text, n); | ||
917 | |||
918 | if (n) { | ||
919 | len -= n; | ||
920 | if (!len) | 953 | if (!len) |
921 | len = -EFAULT; | 954 | len = -EFAULT; |
922 | break; | 955 | break; |
923 | } | 956 | } |
957 | |||
958 | len += n; | ||
959 | size -= n; | ||
960 | buf += n; | ||
924 | } | 961 | } |
925 | 962 | ||
926 | kfree(text); | 963 | kfree(text); |
@@ -941,6 +978,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear) | |||
941 | u64 next_seq; | 978 | u64 next_seq; |
942 | u64 seq; | 979 | u64 seq; |
943 | u32 idx; | 980 | u32 idx; |
981 | enum log_flags prev; | ||
944 | 982 | ||
945 | if (clear_seq < log_first_seq) { | 983 | if (clear_seq < log_first_seq) { |
946 | /* messages are gone, move to first available one */ | 984 | /* messages are gone, move to first available one */ |
@@ -954,10 +992,11 @@ static int syslog_print_all(char __user *buf, int size, bool clear) | |||
954 | */ | 992 | */ |
955 | seq = clear_seq; | 993 | seq = clear_seq; |
956 | idx = clear_idx; | 994 | idx = clear_idx; |
995 | prev = 0; | ||
957 | while (seq < log_next_seq) { | 996 | while (seq < log_next_seq) { |
958 | struct log *msg = log_from_idx(idx); | 997 | struct log *msg = log_from_idx(idx); |
959 | 998 | ||
960 | len += msg_print_text(msg, true, NULL, 0); | 999 | len += msg_print_text(msg, prev, true, NULL, 0); |
961 | idx = log_next(idx); | 1000 | idx = log_next(idx); |
962 | seq++; | 1001 | seq++; |
963 | } | 1002 | } |
@@ -965,10 +1004,11 @@ static int syslog_print_all(char __user *buf, int size, bool clear) | |||
965 | /* move first record forward until length fits into the buffer */ | 1004 | /* move first record forward until length fits into the buffer */ |
966 | seq = clear_seq; | 1005 | seq = clear_seq; |
967 | idx = clear_idx; | 1006 | idx = clear_idx; |
1007 | prev = 0; | ||
968 | while (len > size && seq < log_next_seq) { | 1008 | while (len > size && seq < log_next_seq) { |
969 | struct log *msg = log_from_idx(idx); | 1009 | struct log *msg = log_from_idx(idx); |
970 | 1010 | ||
971 | len -= msg_print_text(msg, true, NULL, 0); | 1011 | len -= msg_print_text(msg, prev, true, NULL, 0); |
972 | idx = log_next(idx); | 1012 | idx = log_next(idx); |
973 | seq++; | 1013 | seq++; |
974 | } | 1014 | } |
@@ -977,17 +1017,19 @@ static int syslog_print_all(char __user *buf, int size, bool clear) | |||
977 | next_seq = log_next_seq; | 1017 | next_seq = log_next_seq; |
978 | 1018 | ||
979 | len = 0; | 1019 | len = 0; |
1020 | prev = 0; | ||
980 | while (len >= 0 && seq < next_seq) { | 1021 | while (len >= 0 && seq < next_seq) { |
981 | struct log *msg = log_from_idx(idx); | 1022 | struct log *msg = log_from_idx(idx); |
982 | int textlen; | 1023 | int textlen; |
983 | 1024 | ||
984 | textlen = msg_print_text(msg, true, text, LOG_LINE_MAX); | 1025 | textlen = msg_print_text(msg, prev, true, text, LOG_LINE_MAX); |
985 | if (textlen < 0) { | 1026 | if (textlen < 0) { |
986 | len = textlen; | 1027 | len = textlen; |
987 | break; | 1028 | break; |
988 | } | 1029 | } |
989 | idx = log_next(idx); | 1030 | idx = log_next(idx); |
990 | seq++; | 1031 | seq++; |
1032 | prev = msg->flags; | ||
991 | 1033 | ||
992 | raw_spin_unlock_irq(&logbuf_lock); | 1034 | raw_spin_unlock_irq(&logbuf_lock); |
993 | if (copy_to_user(buf + len, text, textlen)) | 1035 | if (copy_to_user(buf + len, text, textlen)) |
@@ -1000,6 +1042,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear) | |||
1000 | /* messages are gone, move to next one */ | 1042 | /* messages are gone, move to next one */ |
1001 | seq = log_first_seq; | 1043 | seq = log_first_seq; |
1002 | idx = log_first_idx; | 1044 | idx = log_first_idx; |
1045 | prev = 0; | ||
1003 | } | 1046 | } |
1004 | } | 1047 | } |
1005 | } | 1048 | } |
@@ -1018,7 +1061,6 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) | |||
1018 | { | 1061 | { |
1019 | bool clear = false; | 1062 | bool clear = false; |
1020 | static int saved_console_loglevel = -1; | 1063 | static int saved_console_loglevel = -1; |
1021 | static DEFINE_MUTEX(syslog_mutex); | ||
1022 | int error; | 1064 | int error; |
1023 | 1065 | ||
1024 | error = check_syslog_permissions(type, from_file); | 1066 | error = check_syslog_permissions(type, from_file); |
@@ -1045,17 +1087,11 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) | |||
1045 | error = -EFAULT; | 1087 | error = -EFAULT; |
1046 | goto out; | 1088 | goto out; |
1047 | } | 1089 | } |
1048 | error = mutex_lock_interruptible(&syslog_mutex); | ||
1049 | if (error) | ||
1050 | goto out; | ||
1051 | error = wait_event_interruptible(log_wait, | 1090 | error = wait_event_interruptible(log_wait, |
1052 | syslog_seq != log_next_seq); | 1091 | syslog_seq != log_next_seq); |
1053 | if (error) { | 1092 | if (error) |
1054 | mutex_unlock(&syslog_mutex); | ||
1055 | goto out; | 1093 | goto out; |
1056 | } | ||
1057 | error = syslog_print(buf, len); | 1094 | error = syslog_print(buf, len); |
1058 | mutex_unlock(&syslog_mutex); | ||
1059 | break; | 1095 | break; |
1060 | /* Read/clear last kernel messages */ | 1096 | /* Read/clear last kernel messages */ |
1061 | case SYSLOG_ACTION_READ_CLEAR: | 1097 | case SYSLOG_ACTION_READ_CLEAR: |
@@ -1111,6 +1147,8 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) | |||
1111 | /* messages are gone, move to first one */ | 1147 | /* messages are gone, move to first one */ |
1112 | syslog_seq = log_first_seq; | 1148 | syslog_seq = log_first_seq; |
1113 | syslog_idx = log_first_idx; | 1149 | syslog_idx = log_first_idx; |
1150 | syslog_prev = 0; | ||
1151 | syslog_partial = 0; | ||
1114 | } | 1152 | } |
1115 | if (from_file) { | 1153 | if (from_file) { |
1116 | /* | 1154 | /* |
@@ -1120,19 +1158,20 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) | |||
1120 | */ | 1158 | */ |
1121 | error = log_next_idx - syslog_idx; | 1159 | error = log_next_idx - syslog_idx; |
1122 | } else { | 1160 | } else { |
1123 | u64 seq; | 1161 | u64 seq = syslog_seq; |
1124 | u32 idx; | 1162 | u32 idx = syslog_idx; |
1163 | enum log_flags prev = syslog_prev; | ||
1125 | 1164 | ||
1126 | error = 0; | 1165 | error = 0; |
1127 | seq = syslog_seq; | ||
1128 | idx = syslog_idx; | ||
1129 | while (seq < log_next_seq) { | 1166 | while (seq < log_next_seq) { |
1130 | struct log *msg = log_from_idx(idx); | 1167 | struct log *msg = log_from_idx(idx); |
1131 | 1168 | ||
1132 | error += msg_print_text(msg, true, NULL, 0); | 1169 | error += msg_print_text(msg, prev, true, NULL, 0); |
1133 | idx = log_next(idx); | 1170 | idx = log_next(idx); |
1134 | seq++; | 1171 | seq++; |
1172 | prev = msg->flags; | ||
1135 | } | 1173 | } |
1174 | error -= syslog_partial; | ||
1136 | } | 1175 | } |
1137 | raw_spin_unlock_irq(&logbuf_lock); | 1176 | raw_spin_unlock_irq(&logbuf_lock); |
1138 | break; | 1177 | break; |
@@ -1153,21 +1192,6 @@ SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) | |||
1153 | return do_syslog(type, buf, len, SYSLOG_FROM_CALL); | 1192 | return do_syslog(type, buf, len, SYSLOG_FROM_CALL); |
1154 | } | 1193 | } |
1155 | 1194 | ||
1156 | #ifdef CONFIG_KGDB_KDB | ||
1157 | /* kdb dmesg command needs access to the syslog buffer. do_syslog() | ||
1158 | * uses locks so it cannot be used during debugging. Just tell kdb | ||
1159 | * where the start and end of the physical and logical logs are. This | ||
1160 | * is equivalent to do_syslog(3). | ||
1161 | */ | ||
1162 | void kdb_syslog_data(char *syslog_data[4]) | ||
1163 | { | ||
1164 | syslog_data[0] = log_buf; | ||
1165 | syslog_data[1] = log_buf + log_buf_len; | ||
1166 | syslog_data[2] = log_buf + log_first_idx; | ||
1167 | syslog_data[3] = log_buf + log_next_idx; | ||
1168 | } | ||
1169 | #endif /* CONFIG_KGDB_KDB */ | ||
1170 | |||
1171 | static bool __read_mostly ignore_loglevel; | 1195 | static bool __read_mostly ignore_loglevel; |
1172 | 1196 | ||
1173 | static int __init ignore_loglevel_setup(char *str) | 1197 | static int __init ignore_loglevel_setup(char *str) |
@@ -1400,10 +1424,9 @@ asmlinkage int vprintk_emit(int facility, int level, | |||
1400 | static char textbuf[LOG_LINE_MAX]; | 1424 | static char textbuf[LOG_LINE_MAX]; |
1401 | char *text = textbuf; | 1425 | char *text = textbuf; |
1402 | size_t text_len; | 1426 | size_t text_len; |
1427 | enum log_flags lflags = 0; | ||
1403 | unsigned long flags; | 1428 | unsigned long flags; |
1404 | int this_cpu; | 1429 | int this_cpu; |
1405 | bool newline = false; | ||
1406 | bool prefix = false; | ||
1407 | int printed_len = 0; | 1430 | int printed_len = 0; |
1408 | 1431 | ||
1409 | boot_delay_msec(); | 1432 | boot_delay_msec(); |
@@ -1442,7 +1465,7 @@ asmlinkage int vprintk_emit(int facility, int level, | |||
1442 | recursion_bug = 0; | 1465 | recursion_bug = 0; |
1443 | printed_len += strlen(recursion_msg); | 1466 | printed_len += strlen(recursion_msg); |
1444 | /* emit KERN_CRIT message */ | 1467 | /* emit KERN_CRIT message */ |
1445 | log_store(0, 2, LOG_DEFAULT, 0, | 1468 | log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0, |
1446 | NULL, 0, recursion_msg, printed_len); | 1469 | NULL, 0, recursion_msg, printed_len); |
1447 | } | 1470 | } |
1448 | 1471 | ||
@@ -1455,7 +1478,7 @@ asmlinkage int vprintk_emit(int facility, int level, | |||
1455 | /* mark and strip a trailing newline */ | 1478 | /* mark and strip a trailing newline */ |
1456 | if (text_len && text[text_len-1] == '\n') { | 1479 | if (text_len && text[text_len-1] == '\n') { |
1457 | text_len--; | 1480 | text_len--; |
1458 | newline = true; | 1481 | lflags |= LOG_NEWLINE; |
1459 | } | 1482 | } |
1460 | 1483 | ||
1461 | /* strip syslog prefix and extract log level or control flags */ | 1484 | /* strip syslog prefix and extract log level or control flags */ |
@@ -1465,7 +1488,7 @@ asmlinkage int vprintk_emit(int facility, int level, | |||
1465 | if (level == -1) | 1488 | if (level == -1) |
1466 | level = text[1] - '0'; | 1489 | level = text[1] - '0'; |
1467 | case 'd': /* KERN_DEFAULT */ | 1490 | case 'd': /* KERN_DEFAULT */ |
1468 | prefix = true; | 1491 | lflags |= LOG_PREFIX; |
1469 | case 'c': /* KERN_CONT */ | 1492 | case 'c': /* KERN_CONT */ |
1470 | text += 3; | 1493 | text += 3; |
1471 | text_len -= 3; | 1494 | text_len -= 3; |
@@ -1475,22 +1498,20 @@ asmlinkage int vprintk_emit(int facility, int level, | |||
1475 | if (level == -1) | 1498 | if (level == -1) |
1476 | level = default_message_loglevel; | 1499 | level = default_message_loglevel; |
1477 | 1500 | ||
1478 | if (dict) { | 1501 | if (dict) |
1479 | prefix = true; | 1502 | lflags |= LOG_PREFIX|LOG_NEWLINE; |
1480 | newline = true; | ||
1481 | } | ||
1482 | 1503 | ||
1483 | if (!newline) { | 1504 | if (!(lflags & LOG_NEWLINE)) { |
1484 | /* | 1505 | /* |
1485 | * Flush the conflicting buffer. An earlier newline was missing, | 1506 | * Flush the conflicting buffer. An earlier newline was missing, |
1486 | * or another task also prints continuation lines. | 1507 | * or another task also prints continuation lines. |
1487 | */ | 1508 | */ |
1488 | if (cont.len && (prefix || cont.owner != current)) | 1509 | if (cont.len && (lflags & LOG_PREFIX || cont.owner != current)) |
1489 | cont_flush(); | 1510 | cont_flush(); |
1490 | 1511 | ||
1491 | /* buffer line if possible, otherwise store it right away */ | 1512 | /* buffer line if possible, otherwise store it right away */ |
1492 | if (!cont_add(facility, level, text, text_len)) | 1513 | if (!cont_add(facility, level, text, text_len)) |
1493 | log_store(facility, level, LOG_DEFAULT, 0, | 1514 | log_store(facility, level, lflags | LOG_CONT, 0, |
1494 | dict, dictlen, text, text_len); | 1515 | dict, dictlen, text, text_len); |
1495 | } else { | 1516 | } else { |
1496 | bool stored = false; | 1517 | bool stored = false; |
@@ -1502,13 +1523,13 @@ asmlinkage int vprintk_emit(int facility, int level, | |||
1502 | * flush it out and store this line separately. | 1523 | * flush it out and store this line separately. |
1503 | */ | 1524 | */ |
1504 | if (cont.len && cont.owner == current) { | 1525 | if (cont.len && cont.owner == current) { |
1505 | if (!prefix) | 1526 | if (!(lflags & LOG_PREFIX)) |
1506 | stored = cont_add(facility, level, text, text_len); | 1527 | stored = cont_add(facility, level, text, text_len); |
1507 | cont_flush(); | 1528 | cont_flush(); |
1508 | } | 1529 | } |
1509 | 1530 | ||
1510 | if (!stored) | 1531 | if (!stored) |
1511 | log_store(facility, level, LOG_DEFAULT, 0, | 1532 | log_store(facility, level, lflags, 0, |
1512 | dict, dictlen, text, text_len); | 1533 | dict, dictlen, text, text_len); |
1513 | } | 1534 | } |
1514 | printed_len += text_len; | 1535 | printed_len += text_len; |
@@ -1607,8 +1628,8 @@ static struct cont { | |||
1607 | static struct log *log_from_idx(u32 idx) { return NULL; } | 1628 | static struct log *log_from_idx(u32 idx) { return NULL; } |
1608 | static u32 log_next(u32 idx) { return 0; } | 1629 | static u32 log_next(u32 idx) { return 0; } |
1609 | 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) {} |
1610 | 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, |
1611 | char *buf, size_t size) { return 0; } | 1632 | bool syslog, char *buf, size_t size) { return 0; } |
1612 | static size_t cont_print_text(char *text, size_t size) { return 0; } | 1633 | static size_t cont_print_text(char *text, size_t size) { return 0; } |
1613 | 1634 | ||
1614 | #endif /* CONFIG_PRINTK */ | 1635 | #endif /* CONFIG_PRINTK */ |
@@ -1884,6 +1905,7 @@ void wake_up_klogd(void) | |||
1884 | /* the next printk record to write to the console */ | 1905 | /* the next printk record to write to the console */ |
1885 | static u64 console_seq; | 1906 | static u64 console_seq; |
1886 | static u32 console_idx; | 1907 | static u32 console_idx; |
1908 | static enum log_flags console_prev; | ||
1887 | 1909 | ||
1888 | /** | 1910 | /** |
1889 | * console_unlock - unlock the console system | 1911 | * console_unlock - unlock the console system |
@@ -1944,6 +1966,7 @@ again: | |||
1944 | /* messages are gone, move to first one */ | 1966 | /* messages are gone, move to first one */ |
1945 | console_seq = log_first_seq; | 1967 | console_seq = log_first_seq; |
1946 | console_idx = log_first_idx; | 1968 | console_idx = log_first_idx; |
1969 | console_prev = 0; | ||
1947 | } | 1970 | } |
1948 | skip: | 1971 | skip: |
1949 | if (console_seq == log_next_seq) | 1972 | if (console_seq == log_next_seq) |
@@ -1957,14 +1980,21 @@ skip: | |||
1957 | */ | 1980 | */ |
1958 | console_idx = log_next(console_idx); | 1981 | console_idx = log_next(console_idx); |
1959 | console_seq++; | 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; | ||
1960 | goto skip; | 1989 | goto skip; |
1961 | } | 1990 | } |
1962 | 1991 | ||
1963 | level = msg->level; | 1992 | level = msg->level; |
1964 | len = msg_print_text(msg, false, text, sizeof(text)); | 1993 | len = msg_print_text(msg, console_prev, false, |
1965 | 1994 | text, sizeof(text)); | |
1966 | console_idx = log_next(console_idx); | 1995 | console_idx = log_next(console_idx); |
1967 | console_seq++; | 1996 | console_seq++; |
1997 | console_prev = msg->flags; | ||
1968 | raw_spin_unlock(&logbuf_lock); | 1998 | raw_spin_unlock(&logbuf_lock); |
1969 | 1999 | ||
1970 | stop_critical_timings(); /* don't trace print latency */ | 2000 | stop_critical_timings(); /* don't trace print latency */ |
@@ -2227,6 +2257,7 @@ void register_console(struct console *newcon) | |||
2227 | raw_spin_lock_irqsave(&logbuf_lock, flags); | 2257 | raw_spin_lock_irqsave(&logbuf_lock, flags); |
2228 | console_seq = syslog_seq; | 2258 | console_seq = syslog_seq; |
2229 | console_idx = syslog_idx; | 2259 | console_idx = syslog_idx; |
2260 | console_prev = syslog_prev; | ||
2230 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | 2261 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); |
2231 | /* | 2262 | /* |
2232 | * 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 |
@@ -2479,7 +2510,7 @@ void kmsg_dump(enum kmsg_dump_reason reason) | |||
2479 | } | 2510 | } |
2480 | 2511 | ||
2481 | /** | 2512 | /** |
2482 | * kmsg_dump_get_line - retrieve one kmsg log line | 2513 | * kmsg_dump_get_line_nolock - retrieve one kmsg log line (unlocked version) |
2483 | * @dumper: registered kmsg dumper | 2514 | * @dumper: registered kmsg dumper |
2484 | * @syslog: include the "<4>" prefixes | 2515 | * @syslog: include the "<4>" prefixes |
2485 | * @line: buffer to copy the line to | 2516 | * @line: buffer to copy the line to |
@@ -2494,11 +2525,12 @@ void kmsg_dump(enum kmsg_dump_reason reason) | |||
2494 | * | 2525 | * |
2495 | * A return value of FALSE indicates that there are no more records to | 2526 | * A return value of FALSE indicates that there are no more records to |
2496 | * read. | 2527 | * read. |
2528 | * | ||
2529 | * The function is similar to kmsg_dump_get_line(), but grabs no locks. | ||
2497 | */ | 2530 | */ |
2498 | bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, | 2531 | bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog, |
2499 | char *line, size_t size, size_t *len) | 2532 | char *line, size_t size, size_t *len) |
2500 | { | 2533 | { |
2501 | unsigned long flags; | ||
2502 | struct log *msg; | 2534 | struct log *msg; |
2503 | size_t l = 0; | 2535 | size_t l = 0; |
2504 | bool ret = false; | 2536 | bool ret = false; |
@@ -2506,7 +2538,6 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, | |||
2506 | if (!dumper->active) | 2538 | if (!dumper->active) |
2507 | goto out; | 2539 | goto out; |
2508 | 2540 | ||
2509 | raw_spin_lock_irqsave(&logbuf_lock, flags); | ||
2510 | if (dumper->cur_seq < log_first_seq) { | 2541 | if (dumper->cur_seq < log_first_seq) { |
2511 | /* messages are gone, move to first available one */ | 2542 | /* messages are gone, move to first available one */ |
2512 | dumper->cur_seq = log_first_seq; | 2543 | dumper->cur_seq = log_first_seq; |
@@ -2514,24 +2545,50 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, | |||
2514 | } | 2545 | } |
2515 | 2546 | ||
2516 | /* last entry */ | 2547 | /* last entry */ |
2517 | if (dumper->cur_seq >= log_next_seq) { | 2548 | if (dumper->cur_seq >= log_next_seq) |
2518 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | ||
2519 | goto out; | 2549 | goto out; |
2520 | } | ||
2521 | 2550 | ||
2522 | msg = log_from_idx(dumper->cur_idx); | 2551 | msg = log_from_idx(dumper->cur_idx); |
2523 | l = msg_print_text(msg, syslog, | 2552 | l = msg_print_text(msg, 0, syslog, line, size); |
2524 | line, size); | ||
2525 | 2553 | ||
2526 | dumper->cur_idx = log_next(dumper->cur_idx); | 2554 | dumper->cur_idx = log_next(dumper->cur_idx); |
2527 | dumper->cur_seq++; | 2555 | dumper->cur_seq++; |
2528 | ret = true; | 2556 | ret = true; |
2529 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | ||
2530 | out: | 2557 | out: |
2531 | if (len) | 2558 | if (len) |
2532 | *len = l; | 2559 | *len = l; |
2533 | return ret; | 2560 | return ret; |
2534 | } | 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 | } | ||
2535 | EXPORT_SYMBOL_GPL(kmsg_dump_get_line); | 2592 | EXPORT_SYMBOL_GPL(kmsg_dump_get_line); |
2536 | 2593 | ||
2537 | /** | 2594 | /** |
@@ -2561,6 +2618,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, | |||
2561 | u32 idx; | 2618 | u32 idx; |
2562 | u64 next_seq; | 2619 | u64 next_seq; |
2563 | u32 next_idx; | 2620 | u32 next_idx; |
2621 | enum log_flags prev; | ||
2564 | size_t l = 0; | 2622 | size_t l = 0; |
2565 | bool ret = false; | 2623 | bool ret = false; |
2566 | 2624 | ||
@@ -2583,23 +2641,27 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, | |||
2583 | /* calculate length of entire buffer */ | 2641 | /* calculate length of entire buffer */ |
2584 | seq = dumper->cur_seq; | 2642 | seq = dumper->cur_seq; |
2585 | idx = dumper->cur_idx; | 2643 | idx = dumper->cur_idx; |
2644 | prev = 0; | ||
2586 | while (seq < dumper->next_seq) { | 2645 | while (seq < dumper->next_seq) { |
2587 | struct log *msg = log_from_idx(idx); | 2646 | struct log *msg = log_from_idx(idx); |
2588 | 2647 | ||
2589 | l += msg_print_text(msg, true, NULL, 0); | 2648 | l += msg_print_text(msg, prev, true, NULL, 0); |
2590 | idx = log_next(idx); | 2649 | idx = log_next(idx); |
2591 | seq++; | 2650 | seq++; |
2651 | prev = msg->flags; | ||
2592 | } | 2652 | } |
2593 | 2653 | ||
2594 | /* move first record forward until length fits into the buffer */ | 2654 | /* move first record forward until length fits into the buffer */ |
2595 | seq = dumper->cur_seq; | 2655 | seq = dumper->cur_seq; |
2596 | idx = dumper->cur_idx; | 2656 | idx = dumper->cur_idx; |
2657 | prev = 0; | ||
2597 | while (l > size && seq < dumper->next_seq) { | 2658 | while (l > size && seq < dumper->next_seq) { |
2598 | struct log *msg = log_from_idx(idx); | 2659 | struct log *msg = log_from_idx(idx); |
2599 | 2660 | ||
2600 | l -= msg_print_text(msg, true, NULL, 0); | 2661 | l -= msg_print_text(msg, prev, true, NULL, 0); |
2601 | idx = log_next(idx); | 2662 | idx = log_next(idx); |
2602 | seq++; | 2663 | seq++; |
2664 | prev = msg->flags; | ||
2603 | } | 2665 | } |
2604 | 2666 | ||
2605 | /* last message in next interation */ | 2667 | /* last message in next interation */ |
@@ -2607,14 +2669,14 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, | |||
2607 | next_idx = idx; | 2669 | next_idx = idx; |
2608 | 2670 | ||
2609 | l = 0; | 2671 | l = 0; |
2672 | prev = 0; | ||
2610 | while (seq < dumper->next_seq) { | 2673 | while (seq < dumper->next_seq) { |
2611 | struct log *msg = log_from_idx(idx); | 2674 | struct log *msg = log_from_idx(idx); |
2612 | 2675 | ||
2613 | l += msg_print_text(msg, syslog, | 2676 | l += msg_print_text(msg, prev, syslog, buf + l, size - l); |
2614 | buf + l, size - l); | ||
2615 | |||
2616 | idx = log_next(idx); | 2677 | idx = log_next(idx); |
2617 | seq++; | 2678 | seq++; |
2679 | prev = msg->flags; | ||
2618 | } | 2680 | } |
2619 | 2681 | ||
2620 | dumper->next_seq = next_seq; | 2682 | dumper->next_seq = next_seq; |
@@ -2629,6 +2691,24 @@ out: | |||
2629 | EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer); | 2691 | EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer); |
2630 | 2692 | ||
2631 | /** | 2693 | /** |
2694 | * kmsg_dump_rewind_nolock - reset the interator (unlocked version) | ||
2695 | * @dumper: registered kmsg dumper | ||
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 | /** | ||
2632 | * kmsg_dump_rewind - reset the interator | 2712 | * kmsg_dump_rewind - reset the interator |
2633 | * @dumper: registered kmsg dumper | 2713 | * @dumper: registered kmsg dumper |
2634 | * | 2714 | * |
@@ -2641,10 +2721,7 @@ void kmsg_dump_rewind(struct kmsg_dumper *dumper) | |||
2641 | unsigned long flags; | 2721 | unsigned long flags; |
2642 | 2722 | ||
2643 | raw_spin_lock_irqsave(&logbuf_lock, flags); | 2723 | raw_spin_lock_irqsave(&logbuf_lock, flags); |
2644 | dumper->cur_seq = clear_seq; | 2724 | kmsg_dump_rewind_nolock(dumper); |
2645 | dumper->cur_idx = clear_idx; | ||
2646 | dumper->next_seq = log_next_seq; | ||
2647 | dumper->next_idx = log_next_idx; | ||
2648 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); | 2725 | raw_spin_unlock_irqrestore(&logbuf_lock, flags); |
2649 | } | 2726 | } |
2650 | EXPORT_SYMBOL_GPL(kmsg_dump_rewind); | 2727 | EXPORT_SYMBOL_GPL(kmsg_dump_rewind); |