aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorKay Sievers <kay@vrfy.org>2012-07-09 15:15:42 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-09 15:15:42 -0400
commit5becfb1df5ac8e491338e64b1029685ccad4b39c (patch)
tree10f6ca3f08493881d02a18248f726bd621f3e7a6 /kernel
parenteb02dac93708f581c99858a19162af8ca2b6bfcb (diff)
kmsg: merge continuation records while printing
In (the unlikely) case our continuation merge buffer is busy, we unfortunately can not merge further continuation printk()s into a single record and have to store them separately, which leads to split-up output of these lines when they are printed. Add some flags about newlines and prefix existence to these records and try to reconstruct the full line again, when the separated records are printed. Reported-By: Michael Neuling <mikey@neuling.org> Cc: Dave Jones <davej@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Tested-By: Michael Neuling <mikey@neuling.org> Signed-off-by: Kay Sievers <kay@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/printk.c120
1 files changed, 78 insertions, 42 deletions
diff --git a/kernel/printk.c b/kernel/printk.c
index 50c33411442d..177fa49357a5 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -194,8 +194,10 @@ static int console_may_schedule;
194 */ 194 */
195 195
196enum log_flags { 196enum 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
201struct log { 203struct log {
@@ -217,6 +219,7 @@ 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 */
218static u64 syslog_seq; 220static u64 syslog_seq;
219static u32 syslog_idx; 221static u32 syslog_idx;
222static enum log_flags syslog_prev;
220static size_t syslog_partial; 223static size_t syslog_partial;
221 224
222/* 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 */
@@ -839,13 +842,26 @@ static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
839 return len; 842 return len;
840} 843}
841 844
842static size_t msg_print_text(const struct log *msg, bool syslog, 845static size_t msg_print_text(const struct log *msg, enum log_flags prev,
843 char *buf, size_t size) 846 bool syslog, char *buf, size_t size)
844{ 847{
845 const char *text = log_text(msg); 848 const char *text = log_text(msg);
846 size_t text_size = msg->text_len; 849 size_t text_size = msg->text_len;
850 bool prefix = true;
851 bool newline = true;
847 size_t len = 0; 852 size_t len = 0;
848 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
849 do { 865 do {
850 const char *next = memchr(text, '\n', text_size); 866 const char *next = memchr(text, '\n', text_size);
851 size_t text_len; 867 size_t text_len;
@@ -863,16 +879,22 @@ static size_t msg_print_text(const struct log *msg, bool syslog,
863 text_len + 1>= size - len) 879 text_len + 1>= size - len)
864 break; 880 break;
865 881
866 len += print_prefix(msg, syslog, buf + len); 882 if (prefix)
883 len += print_prefix(msg, syslog, buf + len);
867 memcpy(buf + len, text, text_len); 884 memcpy(buf + len, text, text_len);
868 len += text_len; 885 len += text_len;
869 buf[len++] = '\n'; 886 if (next || newline)
887 buf[len++] = '\n';
870 } else { 888 } else {
871 /* SYSLOG_ACTION_* buffer size only calculation */ 889 /* SYSLOG_ACTION_* buffer size only calculation */
872 len += print_prefix(msg, syslog, NULL); 890 if (prefix)
873 len += text_len + 1; 891 len += print_prefix(msg, syslog, NULL);
892 len += text_len;
893 if (next || newline)
894 len++;
874 } 895 }
875 896
897 prefix = true;
876 text = next; 898 text = next;
877 } while (text); 899 } while (text);
878 900
@@ -898,6 +920,7 @@ static int syslog_print(char __user *buf, int size)
898 /* messages are gone, move to first one */ 920 /* messages are gone, move to first one */
899 syslog_seq = log_first_seq; 921 syslog_seq = log_first_seq;
900 syslog_idx = log_first_idx; 922 syslog_idx = log_first_idx;
923 syslog_prev = 0;
901 syslog_partial = 0; 924 syslog_partial = 0;
902 } 925 }
903 if (syslog_seq == log_next_seq) { 926 if (syslog_seq == log_next_seq) {
@@ -907,11 +930,12 @@ static int syslog_print(char __user *buf, int size)
907 930
908 skip = syslog_partial; 931 skip = syslog_partial;
909 msg = log_from_idx(syslog_idx); 932 msg = log_from_idx(syslog_idx);
910 n = msg_print_text(msg, true, text, LOG_LINE_MAX); 933 n = msg_print_text(msg, syslog_prev, true, text, LOG_LINE_MAX);
911 if (n - syslog_partial <= size) { 934 if (n - syslog_partial <= size) {
912 /* message fits into buffer, move forward */ 935 /* message fits into buffer, move forward */
913 syslog_idx = log_next(syslog_idx); 936 syslog_idx = log_next(syslog_idx);
914 syslog_seq++; 937 syslog_seq++;
938 syslog_prev = msg->flags;
915 n -= syslog_partial; 939 n -= syslog_partial;
916 syslog_partial = 0; 940 syslog_partial = 0;
917 } else if (!len){ 941 } else if (!len){
@@ -954,6 +978,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
954 u64 next_seq; 978 u64 next_seq;
955 u64 seq; 979 u64 seq;
956 u32 idx; 980 u32 idx;
981 enum log_flags prev;
957 982
958 if (clear_seq < log_first_seq) { 983 if (clear_seq < log_first_seq) {
959 /* messages are gone, move to first available one */ 984 /* messages are gone, move to first available one */
@@ -967,10 +992,11 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
967 */ 992 */
968 seq = clear_seq; 993 seq = clear_seq;
969 idx = clear_idx; 994 idx = clear_idx;
995 prev = 0;
970 while (seq < log_next_seq) { 996 while (seq < log_next_seq) {
971 struct log *msg = log_from_idx(idx); 997 struct log *msg = log_from_idx(idx);
972 998
973 len += msg_print_text(msg, true, NULL, 0); 999 len += msg_print_text(msg, prev, true, NULL, 0);
974 idx = log_next(idx); 1000 idx = log_next(idx);
975 seq++; 1001 seq++;
976 } 1002 }
@@ -978,10 +1004,11 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
978 /* move first record forward until length fits into the buffer */ 1004 /* move first record forward until length fits into the buffer */
979 seq = clear_seq; 1005 seq = clear_seq;
980 idx = clear_idx; 1006 idx = clear_idx;
1007 prev = 0;
981 while (len > size && seq < log_next_seq) { 1008 while (len > size && seq < log_next_seq) {
982 struct log *msg = log_from_idx(idx); 1009 struct log *msg = log_from_idx(idx);
983 1010
984 len -= msg_print_text(msg, true, NULL, 0); 1011 len -= msg_print_text(msg, prev, true, NULL, 0);
985 idx = log_next(idx); 1012 idx = log_next(idx);
986 seq++; 1013 seq++;
987 } 1014 }
@@ -990,17 +1017,19 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
990 next_seq = log_next_seq; 1017 next_seq = log_next_seq;
991 1018
992 len = 0; 1019 len = 0;
1020 prev = 0;
993 while (len >= 0 && seq < next_seq) { 1021 while (len >= 0 && seq < next_seq) {
994 struct log *msg = log_from_idx(idx); 1022 struct log *msg = log_from_idx(idx);
995 int textlen; 1023 int textlen;
996 1024
997 textlen = msg_print_text(msg, true, text, LOG_LINE_MAX); 1025 textlen = msg_print_text(msg, prev, true, text, LOG_LINE_MAX);
998 if (textlen < 0) { 1026 if (textlen < 0) {
999 len = textlen; 1027 len = textlen;
1000 break; 1028 break;
1001 } 1029 }
1002 idx = log_next(idx); 1030 idx = log_next(idx);
1003 seq++; 1031 seq++;
1032 prev = msg->flags;
1004 1033
1005 raw_spin_unlock_irq(&logbuf_lock); 1034 raw_spin_unlock_irq(&logbuf_lock);
1006 if (copy_to_user(buf + len, text, textlen)) 1035 if (copy_to_user(buf + len, text, textlen))
@@ -1013,6 +1042,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
1013 /* messages are gone, move to next one */ 1042 /* messages are gone, move to next one */
1014 seq = log_first_seq; 1043 seq = log_first_seq;
1015 idx = log_first_idx; 1044 idx = log_first_idx;
1045 prev = 0;
1016 } 1046 }
1017 } 1047 }
1018 } 1048 }
@@ -1117,6 +1147,7 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
1117 /* messages are gone, move to first one */ 1147 /* messages are gone, move to first one */
1118 syslog_seq = log_first_seq; 1148 syslog_seq = log_first_seq;
1119 syslog_idx = log_first_idx; 1149 syslog_idx = log_first_idx;
1150 syslog_prev = 0;
1120 syslog_partial = 0; 1151 syslog_partial = 0;
1121 } 1152 }
1122 if (from_file) { 1153 if (from_file) {
@@ -1127,18 +1158,18 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
1127 */ 1158 */
1128 error = log_next_idx - syslog_idx; 1159 error = log_next_idx - syslog_idx;
1129 } else { 1160 } else {
1130 u64 seq; 1161 u64 seq = syslog_seq;
1131 u32 idx; 1162 u32 idx = syslog_idx;
1163 enum log_flags prev = syslog_prev;
1132 1164
1133 error = 0; 1165 error = 0;
1134 seq = syslog_seq;
1135 idx = syslog_idx;
1136 while (seq < log_next_seq) { 1166 while (seq < log_next_seq) {
1137 struct log *msg = log_from_idx(idx); 1167 struct log *msg = log_from_idx(idx);
1138 1168
1139 error += msg_print_text(msg, true, NULL, 0); 1169 error += msg_print_text(msg, prev, true, NULL, 0);
1140 idx = log_next(idx); 1170 idx = log_next(idx);
1141 seq++; 1171 seq++;
1172 prev = msg->flags;
1142 } 1173 }
1143 error -= syslog_partial; 1174 error -= syslog_partial;
1144 } 1175 }
@@ -1408,10 +1439,9 @@ asmlinkage int vprintk_emit(int facility, int level,
1408 static char textbuf[LOG_LINE_MAX]; 1439 static char textbuf[LOG_LINE_MAX];
1409 char *text = textbuf; 1440 char *text = textbuf;
1410 size_t text_len; 1441 size_t text_len;
1442 enum log_flags lflags = 0;
1411 unsigned long flags; 1443 unsigned long flags;
1412 int this_cpu; 1444 int this_cpu;
1413 bool newline = false;
1414 bool prefix = false;
1415 int printed_len = 0; 1445 int printed_len = 0;
1416 1446
1417 boot_delay_msec(); 1447 boot_delay_msec();
@@ -1450,7 +1480,7 @@ asmlinkage int vprintk_emit(int facility, int level,
1450 recursion_bug = 0; 1480 recursion_bug = 0;
1451 printed_len += strlen(recursion_msg); 1481 printed_len += strlen(recursion_msg);
1452 /* emit KERN_CRIT message */ 1482 /* emit KERN_CRIT message */
1453 log_store(0, 2, LOG_DEFAULT, 0, 1483 log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
1454 NULL, 0, recursion_msg, printed_len); 1484 NULL, 0, recursion_msg, printed_len);
1455 } 1485 }
1456 1486
@@ -1463,7 +1493,7 @@ asmlinkage int vprintk_emit(int facility, int level,
1463 /* mark and strip a trailing newline */ 1493 /* mark and strip a trailing newline */
1464 if (text_len && text[text_len-1] == '\n') { 1494 if (text_len && text[text_len-1] == '\n') {
1465 text_len--; 1495 text_len--;
1466 newline = true; 1496 lflags |= LOG_NEWLINE;
1467 } 1497 }
1468 1498
1469 /* strip syslog prefix and extract log level or control flags */ 1499 /* strip syslog prefix and extract log level or control flags */
@@ -1473,7 +1503,7 @@ asmlinkage int vprintk_emit(int facility, int level,
1473 if (level == -1) 1503 if (level == -1)
1474 level = text[1] - '0'; 1504 level = text[1] - '0';
1475 case 'd': /* KERN_DEFAULT */ 1505 case 'd': /* KERN_DEFAULT */
1476 prefix = true; 1506 lflags |= LOG_PREFIX;
1477 case 'c': /* KERN_CONT */ 1507 case 'c': /* KERN_CONT */
1478 text += 3; 1508 text += 3;
1479 text_len -= 3; 1509 text_len -= 3;
@@ -1483,22 +1513,20 @@ asmlinkage int vprintk_emit(int facility, int level,
1483 if (level == -1) 1513 if (level == -1)
1484 level = default_message_loglevel; 1514 level = default_message_loglevel;
1485 1515
1486 if (dict) { 1516 if (dict)
1487 prefix = true; 1517 lflags |= LOG_PREFIX|LOG_NEWLINE;
1488 newline = true;
1489 }
1490 1518
1491 if (!newline) { 1519 if (!(lflags & LOG_NEWLINE)) {
1492 /* 1520 /*
1493 * Flush the conflicting buffer. An earlier newline was missing, 1521 * Flush the conflicting buffer. An earlier newline was missing,
1494 * or another task also prints continuation lines. 1522 * or another task also prints continuation lines.
1495 */ 1523 */
1496 if (cont.len && (prefix || cont.owner != current)) 1524 if (cont.len && (lflags & LOG_PREFIX || cont.owner != current))
1497 cont_flush(); 1525 cont_flush();
1498 1526
1499 /* buffer line if possible, otherwise store it right away */ 1527 /* buffer line if possible, otherwise store it right away */
1500 if (!cont_add(facility, level, text, text_len)) 1528 if (!cont_add(facility, level, text, text_len))
1501 log_store(facility, level, LOG_DEFAULT, 0, 1529 log_store(facility, level, lflags | LOG_CONT, 0,
1502 dict, dictlen, text, text_len); 1530 dict, dictlen, text, text_len);
1503 } else { 1531 } else {
1504 bool stored = false; 1532 bool stored = false;
@@ -1510,13 +1538,13 @@ asmlinkage int vprintk_emit(int facility, int level,
1510 * flush it out and store this line separately. 1538 * flush it out and store this line separately.
1511 */ 1539 */
1512 if (cont.len && cont.owner == current) { 1540 if (cont.len && cont.owner == current) {
1513 if (!prefix) 1541 if (!(lflags & LOG_PREFIX))
1514 stored = cont_add(facility, level, text, text_len); 1542 stored = cont_add(facility, level, text, text_len);
1515 cont_flush(); 1543 cont_flush();
1516 } 1544 }
1517 1545
1518 if (!stored) 1546 if (!stored)
1519 log_store(facility, level, LOG_DEFAULT, 0, 1547 log_store(facility, level, lflags, 0,
1520 dict, dictlen, text, text_len); 1548 dict, dictlen, text, text_len);
1521 } 1549 }
1522 printed_len += text_len; 1550 printed_len += text_len;
@@ -1615,8 +1643,8 @@ static struct cont {
1615static struct log *log_from_idx(u32 idx) { return NULL; } 1643static struct log *log_from_idx(u32 idx) { return NULL; }
1616static u32 log_next(u32 idx) { return 0; } 1644static u32 log_next(u32 idx) { return 0; }
1617static void call_console_drivers(int level, const char *text, size_t len) {} 1645static void call_console_drivers(int level, const char *text, size_t len) {}
1618static size_t msg_print_text(const struct log *msg, bool syslog, 1646static size_t msg_print_text(const struct log *msg, enum log_flags prev,
1619 char *buf, size_t size) { return 0; } 1647 bool syslog, char *buf, size_t size) { return 0; }
1620static size_t cont_print_text(char *text, size_t size) { return 0; } 1648static size_t cont_print_text(char *text, size_t size) { return 0; }
1621 1649
1622#endif /* CONFIG_PRINTK */ 1650#endif /* CONFIG_PRINTK */
@@ -1892,6 +1920,7 @@ void wake_up_klogd(void)
1892/* the next printk record to write to the console */ 1920/* the next printk record to write to the console */
1893static u64 console_seq; 1921static u64 console_seq;
1894static u32 console_idx; 1922static u32 console_idx;
1923static enum log_flags console_prev;
1895 1924
1896/** 1925/**
1897 * console_unlock - unlock the console system 1926 * console_unlock - unlock the console system
@@ -1952,6 +1981,7 @@ again:
1952 /* messages are gone, move to first one */ 1981 /* messages are gone, move to first one */
1953 console_seq = log_first_seq; 1982 console_seq = log_first_seq;
1954 console_idx = log_first_idx; 1983 console_idx = log_first_idx;
1984 console_prev = 0;
1955 } 1985 }
1956skip: 1986skip:
1957 if (console_seq == log_next_seq) 1987 if (console_seq == log_next_seq)
@@ -1975,10 +2005,11 @@ skip:
1975 } 2005 }
1976 2006
1977 level = msg->level; 2007 level = msg->level;
1978 len = msg_print_text(msg, false, text, sizeof(text)); 2008 len = msg_print_text(msg, console_prev, false,
1979 2009 text, sizeof(text));
1980 console_idx = log_next(console_idx); 2010 console_idx = log_next(console_idx);
1981 console_seq++; 2011 console_seq++;
2012 console_prev = msg->flags;
1982 raw_spin_unlock(&logbuf_lock); 2013 raw_spin_unlock(&logbuf_lock);
1983 2014
1984 stop_critical_timings(); /* don't trace print latency */ 2015 stop_critical_timings(); /* don't trace print latency */
@@ -2241,6 +2272,7 @@ void register_console(struct console *newcon)
2241 raw_spin_lock_irqsave(&logbuf_lock, flags); 2272 raw_spin_lock_irqsave(&logbuf_lock, flags);
2242 console_seq = syslog_seq; 2273 console_seq = syslog_seq;
2243 console_idx = syslog_idx; 2274 console_idx = syslog_idx;
2275 console_prev = syslog_prev;
2244 raw_spin_unlock_irqrestore(&logbuf_lock, flags); 2276 raw_spin_unlock_irqrestore(&logbuf_lock, flags);
2245 /* 2277 /*
2246 * We're about to replay the log buffer. Only do this to the 2278 * We're about to replay the log buffer. Only do this to the
@@ -2534,8 +2566,7 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
2534 } 2566 }
2535 2567
2536 msg = log_from_idx(dumper->cur_idx); 2568 msg = log_from_idx(dumper->cur_idx);
2537 l = msg_print_text(msg, syslog, 2569 l = msg_print_text(msg, 0, syslog, line, size);
2538 line, size);
2539 2570
2540 dumper->cur_idx = log_next(dumper->cur_idx); 2571 dumper->cur_idx = log_next(dumper->cur_idx);
2541 dumper->cur_seq++; 2572 dumper->cur_seq++;
@@ -2575,6 +2606,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
2575 u32 idx; 2606 u32 idx;
2576 u64 next_seq; 2607 u64 next_seq;
2577 u32 next_idx; 2608 u32 next_idx;
2609 enum log_flags prev;
2578 size_t l = 0; 2610 size_t l = 0;
2579 bool ret = false; 2611 bool ret = false;
2580 2612
@@ -2597,23 +2629,27 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
2597 /* calculate length of entire buffer */ 2629 /* calculate length of entire buffer */
2598 seq = dumper->cur_seq; 2630 seq = dumper->cur_seq;
2599 idx = dumper->cur_idx; 2631 idx = dumper->cur_idx;
2632 prev = 0;
2600 while (seq < dumper->next_seq) { 2633 while (seq < dumper->next_seq) {
2601 struct log *msg = log_from_idx(idx); 2634 struct log *msg = log_from_idx(idx);
2602 2635
2603 l += msg_print_text(msg, true, NULL, 0); 2636 l += msg_print_text(msg, prev, true, NULL, 0);
2604 idx = log_next(idx); 2637 idx = log_next(idx);
2605 seq++; 2638 seq++;
2639 prev = msg->flags;
2606 } 2640 }
2607 2641
2608 /* move first record forward until length fits into the buffer */ 2642 /* move first record forward until length fits into the buffer */
2609 seq = dumper->cur_seq; 2643 seq = dumper->cur_seq;
2610 idx = dumper->cur_idx; 2644 idx = dumper->cur_idx;
2645 prev = 0;
2611 while (l > size && seq < dumper->next_seq) { 2646 while (l > size && seq < dumper->next_seq) {
2612 struct log *msg = log_from_idx(idx); 2647 struct log *msg = log_from_idx(idx);
2613 2648
2614 l -= msg_print_text(msg, true, NULL, 0); 2649 l -= msg_print_text(msg, prev, true, NULL, 0);
2615 idx = log_next(idx); 2650 idx = log_next(idx);
2616 seq++; 2651 seq++;
2652 prev = msg->flags;
2617 } 2653 }
2618 2654
2619 /* last message in next interation */ 2655 /* last message in next interation */
@@ -2621,14 +2657,14 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
2621 next_idx = idx; 2657 next_idx = idx;
2622 2658
2623 l = 0; 2659 l = 0;
2660 prev = 0;
2624 while (seq < dumper->next_seq) { 2661 while (seq < dumper->next_seq) {
2625 struct log *msg = log_from_idx(idx); 2662 struct log *msg = log_from_idx(idx);
2626 2663
2627 l += msg_print_text(msg, syslog, 2664 l += msg_print_text(msg, prev, syslog, buf + l, size - l);
2628 buf + l, size - l);
2629
2630 idx = log_next(idx); 2665 idx = log_next(idx);
2631 seq++; 2666 seq++;
2667 prev = msg->flags;
2632 } 2668 }
2633 2669
2634 dumper->next_seq = next_seq; 2670 dumper->next_seq = next_seq;