diff options
| -rw-r--r-- | kernel/printk.c | 93 |
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; | |||
| 231 | static u64 log_next_seq; | 231 | static u64 log_next_seq; |
| 232 | static u32 log_next_idx; | 232 | static u32 log_next_idx; |
| 233 | 233 | ||
| 234 | /* the next printk record to write to the console */ | ||
| 235 | static u64 console_seq; | ||
| 236 | static u32 console_idx; | ||
| 237 | static 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 */ |
| 235 | static u64 clear_seq; | 240 | static u64 clear_seq; |
| 236 | static u32 clear_idx; | 241 | static 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 | ||
| 1405 | static bool cont_add(int facility, int level, const char *text, size_t len) | 1426 | static 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 |
| 1662 | static u64 syslog_seq; | 1689 | static u64 syslog_seq; |
| 1663 | static u32 syslog_idx; | 1690 | static u32 syslog_idx; |
| 1691 | static u64 console_seq; | ||
| 1692 | static u32 console_idx; | ||
| 1664 | static enum log_flags syslog_prev; | 1693 | static enum log_flags syslog_prev; |
| 1665 | static u64 log_first_seq; | 1694 | static u64 log_first_seq; |
| 1666 | static u32 log_first_idx; | 1695 | static u32 log_first_idx; |
| 1667 | static u64 log_next_seq; | 1696 | static u64 log_next_seq; |
| 1697 | static enum log_flags console_prev; | ||
| 1668 | static struct cont { | 1698 | static 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 */ | 1981 | static void console_cont_flush(char *text, size_t size) |
| 1952 | static u64 console_seq; | 1982 | { |
| 1953 | static u32 console_idx; | 1983 | unsigned long flags; |
| 1954 | static 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; | ||
| 2006 | out: | ||
| 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 | |||
| 1999 | again: | 2041 | again: |
| 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 | ||
