aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-10-09 14:53:00 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-09 15:23:40 -0400
commit5e467652ffefb84b1159d5d8fda665c48e5fd840 (patch)
treebed19a06e5984b1d05816bd0a8e8178f0fef6aa4
parentc362c7ff84634390b44cc1ae7808519596de162d (diff)
printk: re-organize log_output() to be more legible
Avoid some duplicate logic now that we can return early, and update the comments for the new LOG_CONT world order. This also stops the continuation flushing from just using random record flags for the flushing action, instead taking the flags from the proper original line and updating them as we add continuations to it. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--kernel/printk/printk.c62
1 files changed, 27 insertions, 35 deletions
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 090e201244d8..f6fe60d725dd 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1640,35 +1640,33 @@ static struct cont {
1640 bool flushed:1; /* buffer sealed and committed */ 1640 bool flushed:1; /* buffer sealed and committed */
1641} cont; 1641} cont;
1642 1642
1643static void cont_flush(enum log_flags flags) 1643static void cont_flush(void)
1644{ 1644{
1645 if (cont.flushed) 1645 if (cont.flushed)
1646 return; 1646 return;
1647 if (cont.len == 0) 1647 if (cont.len == 0)
1648 return; 1648 return;
1649
1650 if (cont.cons) { 1649 if (cont.cons) {
1651 /* 1650 /*
1652 * If a fragment of this line was directly flushed to the 1651 * If a fragment of this line was directly flushed to the
1653 * console; wait for the console to pick up the rest of the 1652 * console; wait for the console to pick up the rest of the
1654 * line. LOG_NOCONS suppresses a duplicated output. 1653 * line. LOG_NOCONS suppresses a duplicated output.
1655 */ 1654 */
1656 log_store(cont.facility, cont.level, flags | LOG_NOCONS, 1655 log_store(cont.facility, cont.level, cont.flags | LOG_NOCONS,
1657 cont.ts_nsec, NULL, 0, cont.buf, cont.len); 1656 cont.ts_nsec, NULL, 0, cont.buf, cont.len);
1658 cont.flags = flags;
1659 cont.flushed = true; 1657 cont.flushed = true;
1660 } else { 1658 } else {
1661 /* 1659 /*
1662 * If no fragment of this line ever reached the console, 1660 * If no fragment of this line ever reached the console,
1663 * just submit it to the store and free the buffer. 1661 * just submit it to the store and free the buffer.
1664 */ 1662 */
1665 log_store(cont.facility, cont.level, flags, 0, 1663 log_store(cont.facility, cont.level, cont.flags, 0,
1666 NULL, 0, cont.buf, cont.len); 1664 NULL, 0, cont.buf, cont.len);
1667 cont.len = 0; 1665 cont.len = 0;
1668 } 1666 }
1669} 1667}
1670 1668
1671static bool cont_add(int facility, int level, const char *text, size_t len) 1669static bool cont_add(int facility, int level, enum log_flags flags, const char *text, size_t len)
1672{ 1670{
1673 if (cont.len && cont.flushed) 1671 if (cont.len && cont.flushed)
1674 return false; 1672 return false;
@@ -1679,7 +1677,7 @@ static bool cont_add(int facility, int level, const char *text, size_t len)
1679 * the line gets too long, split it up in separate records. 1677 * the line gets too long, split it up in separate records.
1680 */ 1678 */
1681 if (nr_ext_console_drivers || cont.len + len > sizeof(cont.buf)) { 1679 if (nr_ext_console_drivers || cont.len + len > sizeof(cont.buf)) {
1682 cont_flush(LOG_CONT); 1680 cont_flush();
1683 return false; 1681 return false;
1684 } 1682 }
1685 1683
@@ -1688,7 +1686,7 @@ static bool cont_add(int facility, int level, const char *text, size_t len)
1688 cont.level = level; 1686 cont.level = level;
1689 cont.owner = current; 1687 cont.owner = current;
1690 cont.ts_nsec = local_clock(); 1688 cont.ts_nsec = local_clock();
1691 cont.flags = 0; 1689 cont.flags = flags;
1692 cont.cons = 0; 1690 cont.cons = 0;
1693 cont.flushed = false; 1691 cont.flushed = false;
1694 } 1692 }
@@ -1696,8 +1694,15 @@ static bool cont_add(int facility, int level, const char *text, size_t len)
1696 memcpy(cont.buf + cont.len, text, len); 1694 memcpy(cont.buf + cont.len, text, len);
1697 cont.len += len; 1695 cont.len += len;
1698 1696
1697 // The original flags come from the first line,
1698 // but later continuations can add a newline.
1699 if (flags & LOG_NEWLINE) {
1700 cont.flags |= LOG_NEWLINE;
1701 cont_flush();
1702 }
1703
1699 if (cont.len > (sizeof(cont.buf) * 80) / 100) 1704 if (cont.len > (sizeof(cont.buf) * 80) / 100)
1700 cont_flush(LOG_CONT); 1705 cont_flush();
1701 1706
1702 return true; 1707 return true;
1703} 1708}
@@ -1732,39 +1737,26 @@ static size_t cont_print_text(char *text, size_t size)
1732 1737
1733static size_t log_output(int facility, int level, enum log_flags lflags, const char *dict, size_t dictlen, char *text, size_t text_len) 1738static size_t log_output(int facility, int level, enum log_flags lflags, const char *dict, size_t dictlen, char *text, size_t text_len)
1734{ 1739{
1735 if (!(lflags & LOG_NEWLINE)) {
1736 /*
1737 * Flush the conflicting buffer. An earlier newline was missing,
1738 * or another task also prints continuation lines.
1739 */
1740 if (cont.len && (!(lflags & LOG_CONT) || cont.owner != current))
1741 cont_flush(LOG_NEWLINE);
1742
1743 /* buffer line if possible, otherwise store it right away */
1744 if (cont_add(facility, level, text, text_len))
1745 return text_len;
1746
1747 return log_store(facility, level, lflags | LOG_CONT, 0, dict, dictlen, text, text_len);
1748 }
1749
1750 /* 1740 /*
1751 * If an earlier newline was missing and it was the same task, 1741 * If an earlier line was buffered, and we're a continuation
1752 * either merge it with the current buffer and flush, or if 1742 * write from the same process, try to add it to the buffer.
1753 * there was a race with interrupts (prefix == true) then just
1754 * flush it out and store this line separately.
1755 * If the preceding printk was from a different task and missed
1756 * a newline, flush and append the newline.
1757 */ 1743 */
1758 if (cont.len) { 1744 if (cont.len) {
1759 bool stored = false; 1745 if (cont.owner == current && (lflags & LOG_CONT)) {
1746 if (cont_add(facility, level, lflags, text, text_len))
1747 return text_len;
1748 }
1749 /* Otherwise, make sure it's flushed */
1750 cont_flush();
1751 }
1760 1752
1761 if (cont.owner == current && (lflags & LOG_CONT)) 1753 /* If it doesn't end in a newline, try to buffer the current line */
1762 stored = cont_add(facility, level, text, text_len); 1754 if (!(lflags & LOG_NEWLINE)) {
1763 cont_flush(LOG_NEWLINE); 1755 if (cont_add(facility, level, lflags, text, text_len))
1764 if (stored)
1765 return text_len; 1756 return text_len;
1766 } 1757 }
1767 1758
1759 /* Store it in the record log */
1768 return log_store(facility, level, lflags, 0, dict, dictlen, text, text_len); 1760 return log_store(facility, level, lflags, 0, dict, dictlen, text, text_len);
1769} 1761}
1770 1762