aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorKay Sievers <kay@vrfy.org>2012-07-16 21:35:30 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-16 21:35:30 -0400
commiteab072609e11a357181806ab5a5c309ef6eb76f5 (patch)
treeffad9e6097c3a29fa3a54409e0ba9f551565dcfe /kernel
parentd39f3d77c9b1fe7cc33a14beb4a4849af0a4ac22 (diff)
kmsg - do not flush partial lines when the console is busy
Fragments of continuation lines are flushed to the console immediately. In case the console is locked, the fragment must be queued up in the cont buffer. If the the console is busy and the continuation line is complete, but no part of it was written to the console up to this point, we can just store the entire line as a regular record and free the buffer earlier. If the console is busy and earlier messages are already queued up, we should not flush the fragments of continuation lines, but store them after the queued up messages, to ensure the proper ordering. This keeps the console output better readable in case printk()s race against each other, or we receive over-long continuation lines we need to flush. 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.c93
1 files changed, 68 insertions, 25 deletions
diff --git a/kernel/printk.c b/kernel/printk.c
index a41106e19077..4da2377131b0 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -231,6 +231,11 @@ static u32 log_first_idx;
231static u64 log_next_seq; 231static u64 log_next_seq;
232static u32 log_next_idx; 232static u32 log_next_idx;
233 233
234/* the next printk record to write to the console */
235static u64 console_seq;
236static u32 console_idx;
237static enum log_flags console_prev;
238
234/* the next printk record to read after the last 'clear' command */ 239/* the next printk record to read after the last 'clear' command */
235static u64 clear_seq; 240static u64 clear_seq;
236static u32 clear_idx; 241static u32 clear_idx;
@@ -1386,6 +1391,7 @@ static struct cont {
1386 u64 ts_nsec; /* time of first print */ 1391 u64 ts_nsec; /* time of first print */
1387 u8 level; /* log level of first message */ 1392 u8 level; /* log level of first message */
1388 u8 facility; /* log level of first message */ 1393 u8 facility; /* log level of first message */
1394 enum log_flags flags; /* prefix, newline flags */
1389 bool flushed:1; /* buffer sealed and committed */ 1395 bool flushed:1; /* buffer sealed and committed */
1390} cont; 1396} cont;
1391 1397
@@ -1396,10 +1402,25 @@ static void cont_flush(enum log_flags flags)
1396 if (cont.len == 0) 1402 if (cont.len == 0)
1397 return; 1403 return;
1398 1404
1399 log_store(cont.facility, cont.level, LOG_NOCONS | flags, 1405 if (cont.cons) {
1400 cont.ts_nsec, NULL, 0, cont.buf, cont.len); 1406 /*
1401 1407 * If a fragment of this line was directly flushed to the
1402 cont.flushed = true; 1408 * console; wait for the console to pick up the rest of the
1409 * line. LOG_NOCONS suppresses a duplicated output.
1410 */
1411 log_store(cont.facility, cont.level, flags | LOG_NOCONS,
1412 cont.ts_nsec, NULL, 0, cont.buf, cont.len);
1413 cont.flags = flags;
1414 cont.flushed = true;
1415 } else {
1416 /*
1417 * If no fragment of this line ever reached the console,
1418 * just submit it to the store and free the buffer.
1419 */
1420 log_store(cont.facility, cont.level, flags, 0,
1421 NULL, 0, cont.buf, cont.len);
1422 cont.len = 0;
1423 }
1403} 1424}
1404 1425
1405static bool cont_add(int facility, int level, const char *text, size_t len) 1426static bool cont_add(int facility, int level, const char *text, size_t len)
@@ -1418,12 +1439,17 @@ static bool cont_add(int facility, int level, const char *text, size_t len)
1418 cont.level = level; 1439 cont.level = level;
1419 cont.owner = current; 1440 cont.owner = current;
1420 cont.ts_nsec = local_clock(); 1441 cont.ts_nsec = local_clock();
1442 cont.flags = 0;
1421 cont.cons = 0; 1443 cont.cons = 0;
1422 cont.flushed = false; 1444 cont.flushed = false;
1423 } 1445 }
1424 1446
1425 memcpy(cont.buf + cont.len, text, len); 1447 memcpy(cont.buf + cont.len, text, len);
1426 cont.len += len; 1448 cont.len += len;
1449
1450 if (cont.len > (sizeof(cont.buf) * 80) / 100)
1451 cont_flush(LOG_CONT);
1452
1427 return true; 1453 return true;
1428} 1454}
1429 1455
@@ -1432,7 +1458,7 @@ static size_t cont_print_text(char *text, size_t size)
1432 size_t textlen = 0; 1458 size_t textlen = 0;
1433 size_t len; 1459 size_t len;
1434 1460
1435 if (cont.cons == 0) { 1461 if (cont.cons == 0 && (console_prev & LOG_NEWLINE)) {
1436 textlen += print_time(cont.ts_nsec, text); 1462 textlen += print_time(cont.ts_nsec, text);
1437 size -= textlen; 1463 size -= textlen;
1438 } 1464 }
@@ -1447,7 +1473,8 @@ static size_t cont_print_text(char *text, size_t size)
1447 } 1473 }
1448 1474
1449 if (cont.flushed) { 1475 if (cont.flushed) {
1450 text[textlen++] = '\n'; 1476 if (cont.flags & LOG_NEWLINE)
1477 text[textlen++] = '\n';
1451 /* got everything, release buffer */ 1478 /* got everything, release buffer */
1452 cont.len = 0; 1479 cont.len = 0;
1453 } 1480 }
@@ -1545,7 +1572,7 @@ asmlinkage int vprintk_emit(int facility, int level,
1545 * or another task also prints continuation lines. 1572 * or another task also prints continuation lines.
1546 */ 1573 */
1547 if (cont.len && (lflags & LOG_PREFIX || cont.owner != current)) 1574 if (cont.len && (lflags & LOG_PREFIX || cont.owner != current))
1548 cont_flush(0); 1575 cont_flush(LOG_NEWLINE);
1549 1576
1550 /* buffer line if possible, otherwise store it right away */ 1577 /* buffer line if possible, otherwise store it right away */
1551 if (!cont_add(facility, level, text, text_len)) 1578 if (!cont_add(facility, level, text, text_len))
@@ -1563,7 +1590,7 @@ asmlinkage int vprintk_emit(int facility, int level,
1563 if (cont.len && cont.owner == current) { 1590 if (cont.len && cont.owner == current) {
1564 if (!(lflags & LOG_PREFIX)) 1591 if (!(lflags & LOG_PREFIX))
1565 stored = cont_add(facility, level, text, text_len); 1592 stored = cont_add(facility, level, text, text_len);
1566 cont_flush(0); 1593 cont_flush(LOG_NEWLINE);
1567 } 1594 }
1568 1595
1569 if (!stored) 1596 if (!stored)
@@ -1661,10 +1688,13 @@ EXPORT_SYMBOL(printk);
1661#define LOG_LINE_MAX 0 1688#define LOG_LINE_MAX 0
1662static u64 syslog_seq; 1689static u64 syslog_seq;
1663static u32 syslog_idx; 1690static u32 syslog_idx;
1691static u64 console_seq;
1692static u32 console_idx;
1664static enum log_flags syslog_prev; 1693static enum log_flags syslog_prev;
1665static u64 log_first_seq; 1694static u64 log_first_seq;
1666static u32 log_first_idx; 1695static u32 log_first_idx;
1667static u64 log_next_seq; 1696static u64 log_next_seq;
1697static enum log_flags console_prev;
1668static struct cont { 1698static struct cont {
1669 size_t len; 1699 size_t len;
1670 size_t cons; 1700 size_t cons;
@@ -1948,10 +1978,34 @@ void wake_up_klogd(void)
1948 this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP); 1978 this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
1949} 1979}
1950 1980
1951/* the next printk record to write to the console */ 1981static void console_cont_flush(char *text, size_t size)
1952static u64 console_seq; 1982{
1953static u32 console_idx; 1983 unsigned long flags;
1954static enum log_flags console_prev; 1984 size_t len;
1985
1986 raw_spin_lock_irqsave(&logbuf_lock, flags);
1987
1988 if (!cont.len)
1989 goto out;
1990
1991 /*
1992 * We still queue earlier records, likely because the console was
1993 * busy. The earlier ones need to be printed before this one, we
1994 * did not flush any fragment so far, so just let it queue up.
1995 */
1996 if (console_seq < log_next_seq && !cont.cons)
1997 goto out;
1998
1999 len = cont_print_text(text, size);
2000 raw_spin_unlock(&logbuf_lock);
2001 stop_critical_timings();
2002 call_console_drivers(cont.level, text, len);
2003 start_critical_timings();
2004 local_irq_restore(flags);
2005 return;
2006out:
2007 raw_spin_unlock_irqrestore(&logbuf_lock, flags);
2008}
1955 2009
1956/** 2010/**
1957 * console_unlock - unlock the console system 2011 * console_unlock - unlock the console system
@@ -1983,19 +2037,7 @@ void console_unlock(void)
1983 console_may_schedule = 0; 2037 console_may_schedule = 0;
1984 2038
1985 /* flush buffered message fragment immediately to console */ 2039 /* flush buffered message fragment immediately to console */
1986 raw_spin_lock_irqsave(&logbuf_lock, flags); 2040 console_cont_flush(text, sizeof(text));
1987 if (cont.len && (cont.cons < cont.len || cont.flushed)) {
1988 size_t len;
1989
1990 len = cont_print_text(text, sizeof(text));
1991 raw_spin_unlock(&logbuf_lock);
1992 stop_critical_timings();
1993 call_console_drivers(cont.level, text, len);
1994 start_critical_timings();
1995 local_irq_restore(flags);
1996 } else
1997 raw_spin_unlock_irqrestore(&logbuf_lock, flags);
1998
1999again: 2041again:
2000 for (;;) { 2042 for (;;) {
2001 struct log *msg; 2043 struct log *msg;
@@ -2032,6 +2074,7 @@ skip:
2032 * will properly dump everything later. 2074 * will properly dump everything later.
2033 */ 2075 */
2034 msg->flags &= ~LOG_NOCONS; 2076 msg->flags &= ~LOG_NOCONS;
2077 console_prev = msg->flags;
2035 goto skip; 2078 goto skip;
2036 } 2079 }
2037 2080