aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-10-10 12:29:50 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-10 12:29:50 -0400
commit563873318d328d9bbab4b00dfd835ac7c7e28697 (patch)
tree0fcdebe4abb52d340c144efd0a494c217b2c58ba
parent24532f768121b07b16178ffb40442ece43365cbd (diff)
parentbfd8d3f23b51018388be0411ccbc2d56277fe294 (diff)
Merge branch 'printk-cleanups'
Merge my system logging cleanups, triggered by the broken '\n' patches. The line continuation handling has been broken basically forever, and the code to handle the system log records was both confusing and dubious. And it would do entirely the wrong thing unless you always had a terminating newline, partly because it couldn't actually see whether a message was marked KERN_CONT or not (but partly because the LOG_CONT handling in the recording code was rather confusing too). This re-introduces a real semantically meaningful KERN_CONT, and fixes the few places I noticed where it was missing. There are probably more missing cases, since KERN_CONT hasn't actually had any semantic meaning for at least four years (other than the checkpatch meaning of "no log level necessary, this is a continuation line"). This also allows the combination of KERN_CONT and a log level. In that case the log level will be ignored if the merging with a previous line is successful, but if a new record is needed, that new record will now get the right log level. That also means that you can at least in theory combine KERN_CONT with the "pr_info()" style helpers, although any use of pr_fmt() prefixing would make that just result in a mess, of course (the prefix would end up in the middle of a continuing line). * printk-cleanups: printk: make reading the kernel log flush pending lines printk: re-organize log_output() to be more legible printk: split out core logging code into helper function printk: reinstate KERN_CONT for printing continuation lines
-rw-r--r--drivers/tty/vt/vt.c6
-rw-r--r--include/linux/kern_levels.h2
-rw-r--r--include/linux/printk.h1
-rw-r--r--kernel/printk/printk.c124
-rw-r--r--security/selinux/ss/policydb.c4
5 files changed, 68 insertions, 69 deletions
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index e841a4e0e726..06fb39c1d6dd 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -3187,11 +3187,11 @@ static int do_bind_con_driver(const struct consw *csw, int first, int last,
3187 3187
3188 pr_info("Console: switching "); 3188 pr_info("Console: switching ");
3189 if (!deflt) 3189 if (!deflt)
3190 printk("consoles %d-%d ", first+1, last+1); 3190 printk(KERN_CONT "consoles %d-%d ", first+1, last+1);
3191 if (j >= 0) { 3191 if (j >= 0) {
3192 struct vc_data *vc = vc_cons[j].d; 3192 struct vc_data *vc = vc_cons[j].d;
3193 3193
3194 printk("to %s %s %dx%d\n", 3194 printk(KERN_CONT "to %s %s %dx%d\n",
3195 vc->vc_can_do_color ? "colour" : "mono", 3195 vc->vc_can_do_color ? "colour" : "mono",
3196 desc, vc->vc_cols, vc->vc_rows); 3196 desc, vc->vc_cols, vc->vc_rows);
3197 3197
@@ -3200,7 +3200,7 @@ static int do_bind_con_driver(const struct consw *csw, int first, int last,
3200 update_screen(vc); 3200 update_screen(vc);
3201 } 3201 }
3202 } else 3202 } else
3203 printk("to %s\n", desc); 3203 printk(KERN_CONT "to %s\n", desc);
3204 3204
3205 retval = 0; 3205 retval = 0;
3206err: 3206err:
diff --git a/include/linux/kern_levels.h b/include/linux/kern_levels.h
index c2ce155d83cc..f282d4e87258 100644
--- a/include/linux/kern_levels.h
+++ b/include/linux/kern_levels.h
@@ -20,7 +20,7 @@
20 * line that had no enclosing \n). Only to be used by core/arch code 20 * line that had no enclosing \n). Only to be used by core/arch code
21 * during early bootup (a continued line is not SMP-safe otherwise). 21 * during early bootup (a continued line is not SMP-safe otherwise).
22 */ 22 */
23#define KERN_CONT "" 23#define KERN_CONT KERN_SOH "c"
24 24
25/* integer equivalents of KERN_<LEVEL> */ 25/* integer equivalents of KERN_<LEVEL> */
26#define LOGLEVEL_SCHED -2 /* Deferred messages from sched code 26#define LOGLEVEL_SCHED -2 /* Deferred messages from sched code
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 696a56be7d3e..eac1af8502bb 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -16,6 +16,7 @@ static inline int printk_get_level(const char *buffer)
16 switch (buffer[1]) { 16 switch (buffer[1]) {
17 case '0' ... '7': 17 case '0' ... '7':
18 case 'd': /* KERN_DEFAULT */ 18 case 'd': /* KERN_DEFAULT */
19 case 'c': /* KERN_CONT */
19 return buffer[1]; 20 return buffer[1];
20 } 21 }
21 } 22 }
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 8019cc0d3a73..d5e397315473 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -666,11 +666,8 @@ static ssize_t msg_print_ext_header(char *buf, size_t size,
666 * better readable output. 'c' in the record flags mark the first 666 * better readable output. 'c' in the record flags mark the first
667 * fragment of a line, '+' the following. 667 * fragment of a line, '+' the following.
668 */ 668 */
669 if (msg->flags & LOG_CONT && !(prev_flags & LOG_CONT)) 669 if (msg->flags & LOG_CONT)
670 cont = 'c'; 670 cont = (prev_flags & LOG_CONT) ? '+' : 'c';
671 else if ((msg->flags & LOG_CONT) ||
672 ((prev_flags & LOG_CONT) && !(msg->flags & LOG_PREFIX)))
673 cont = '+';
674 671
675 return scnprintf(buf, size, "%u,%llu,%llu,%c;", 672 return scnprintf(buf, size, "%u,%llu,%llu,%c;",
676 (msg->facility << 3) | msg->level, seq, ts_usec, cont); 673 (msg->facility << 3) | msg->level, seq, ts_usec, cont);
@@ -797,6 +794,8 @@ static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from)
797 return ret; 794 return ret;
798} 795}
799 796
797static void cont_flush(void);
798
800static ssize_t devkmsg_read(struct file *file, char __user *buf, 799static ssize_t devkmsg_read(struct file *file, char __user *buf,
801 size_t count, loff_t *ppos) 800 size_t count, loff_t *ppos)
802{ 801{
@@ -812,6 +811,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
812 if (ret) 811 if (ret)
813 return ret; 812 return ret;
814 raw_spin_lock_irq(&logbuf_lock); 813 raw_spin_lock_irq(&logbuf_lock);
814 cont_flush();
815 while (user->seq == log_next_seq) { 815 while (user->seq == log_next_seq) {
816 if (file->f_flags & O_NONBLOCK) { 816 if (file->f_flags & O_NONBLOCK) {
817 ret = -EAGAIN; 817 ret = -EAGAIN;
@@ -874,6 +874,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
874 return -ESPIPE; 874 return -ESPIPE;
875 875
876 raw_spin_lock_irq(&logbuf_lock); 876 raw_spin_lock_irq(&logbuf_lock);
877 cont_flush();
877 switch (whence) { 878 switch (whence) {
878 case SEEK_SET: 879 case SEEK_SET:
879 /* the first record */ 880 /* the first record */
@@ -912,6 +913,7 @@ static unsigned int devkmsg_poll(struct file *file, poll_table *wait)
912 poll_wait(file, &log_wait, wait); 913 poll_wait(file, &log_wait, wait);
913 914
914 raw_spin_lock_irq(&logbuf_lock); 915 raw_spin_lock_irq(&logbuf_lock);
916 cont_flush();
915 if (user->seq < log_next_seq) { 917 if (user->seq < log_next_seq) {
916 /* return error when data has vanished underneath us */ 918 /* return error when data has vanished underneath us */
917 if (user->seq < log_first_seq) 919 if (user->seq < log_first_seq)
@@ -1298,6 +1300,7 @@ static int syslog_print(char __user *buf, int size)
1298 size_t skip; 1300 size_t skip;
1299 1301
1300 raw_spin_lock_irq(&logbuf_lock); 1302 raw_spin_lock_irq(&logbuf_lock);
1303 cont_flush();
1301 if (syslog_seq < log_first_seq) { 1304 if (syslog_seq < log_first_seq) {
1302 /* messages are gone, move to first one */ 1305 /* messages are gone, move to first one */
1303 syslog_seq = log_first_seq; 1306 syslog_seq = log_first_seq;
@@ -1357,6 +1360,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
1357 return -ENOMEM; 1360 return -ENOMEM;
1358 1361
1359 raw_spin_lock_irq(&logbuf_lock); 1362 raw_spin_lock_irq(&logbuf_lock);
1363 cont_flush();
1360 if (buf) { 1364 if (buf) {
1361 u64 next_seq; 1365 u64 next_seq;
1362 u64 seq; 1366 u64 seq;
@@ -1518,6 +1522,7 @@ int do_syslog(int type, char __user *buf, int len, int source)
1518 /* Number of chars in the log buffer */ 1522 /* Number of chars in the log buffer */
1519 case SYSLOG_ACTION_SIZE_UNREAD: 1523 case SYSLOG_ACTION_SIZE_UNREAD:
1520 raw_spin_lock_irq(&logbuf_lock); 1524 raw_spin_lock_irq(&logbuf_lock);
1525 cont_flush();
1521 if (syslog_seq < log_first_seq) { 1526 if (syslog_seq < log_first_seq) {
1522 /* messages are gone, move to first one */ 1527 /* messages are gone, move to first one */
1523 syslog_seq = log_first_seq; 1528 syslog_seq = log_first_seq;
@@ -1654,35 +1659,33 @@ static struct cont {
1654 bool flushed:1; /* buffer sealed and committed */ 1659 bool flushed:1; /* buffer sealed and committed */
1655} cont; 1660} cont;
1656 1661
1657static void cont_flush(enum log_flags flags) 1662static void cont_flush(void)
1658{ 1663{
1659 if (cont.flushed) 1664 if (cont.flushed)
1660 return; 1665 return;
1661 if (cont.len == 0) 1666 if (cont.len == 0)
1662 return; 1667 return;
1663
1664 if (cont.cons) { 1668 if (cont.cons) {
1665 /* 1669 /*
1666 * If a fragment of this line was directly flushed to the 1670 * If a fragment of this line was directly flushed to the
1667 * console; wait for the console to pick up the rest of the 1671 * console; wait for the console to pick up the rest of the
1668 * line. LOG_NOCONS suppresses a duplicated output. 1672 * line. LOG_NOCONS suppresses a duplicated output.
1669 */ 1673 */
1670 log_store(cont.facility, cont.level, flags | LOG_NOCONS, 1674 log_store(cont.facility, cont.level, cont.flags | LOG_NOCONS,
1671 cont.ts_nsec, NULL, 0, cont.buf, cont.len); 1675 cont.ts_nsec, NULL, 0, cont.buf, cont.len);
1672 cont.flags = flags;
1673 cont.flushed = true; 1676 cont.flushed = true;
1674 } else { 1677 } else {
1675 /* 1678 /*
1676 * If no fragment of this line ever reached the console, 1679 * If no fragment of this line ever reached the console,
1677 * just submit it to the store and free the buffer. 1680 * just submit it to the store and free the buffer.
1678 */ 1681 */
1679 log_store(cont.facility, cont.level, flags, 0, 1682 log_store(cont.facility, cont.level, cont.flags, 0,
1680 NULL, 0, cont.buf, cont.len); 1683 NULL, 0, cont.buf, cont.len);
1681 cont.len = 0; 1684 cont.len = 0;
1682 } 1685 }
1683} 1686}
1684 1687
1685static bool cont_add(int facility, int level, const char *text, size_t len) 1688static bool cont_add(int facility, int level, enum log_flags flags, const char *text, size_t len)
1686{ 1689{
1687 if (cont.len && cont.flushed) 1690 if (cont.len && cont.flushed)
1688 return false; 1691 return false;
@@ -1693,7 +1696,7 @@ static bool cont_add(int facility, int level, const char *text, size_t len)
1693 * the line gets too long, split it up in separate records. 1696 * the line gets too long, split it up in separate records.
1694 */ 1697 */
1695 if (nr_ext_console_drivers || cont.len + len > sizeof(cont.buf)) { 1698 if (nr_ext_console_drivers || cont.len + len > sizeof(cont.buf)) {
1696 cont_flush(LOG_CONT); 1699 cont_flush();
1697 return false; 1700 return false;
1698 } 1701 }
1699 1702
@@ -1702,7 +1705,7 @@ static bool cont_add(int facility, int level, const char *text, size_t len)
1702 cont.level = level; 1705 cont.level = level;
1703 cont.owner = current; 1706 cont.owner = current;
1704 cont.ts_nsec = local_clock(); 1707 cont.ts_nsec = local_clock();
1705 cont.flags = 0; 1708 cont.flags = flags;
1706 cont.cons = 0; 1709 cont.cons = 0;
1707 cont.flushed = false; 1710 cont.flushed = false;
1708 } 1711 }
@@ -1710,8 +1713,15 @@ static bool cont_add(int facility, int level, const char *text, size_t len)
1710 memcpy(cont.buf + cont.len, text, len); 1713 memcpy(cont.buf + cont.len, text, len);
1711 cont.len += len; 1714 cont.len += len;
1712 1715
1716 // The original flags come from the first line,
1717 // but later continuations can add a newline.
1718 if (flags & LOG_NEWLINE) {
1719 cont.flags |= LOG_NEWLINE;
1720 cont_flush();
1721 }
1722
1713 if (cont.len > (sizeof(cont.buf) * 80) / 100) 1723 if (cont.len > (sizeof(cont.buf) * 80) / 100)
1714 cont_flush(LOG_CONT); 1724 cont_flush();
1715 1725
1716 return true; 1726 return true;
1717} 1727}
@@ -1744,6 +1754,31 @@ static size_t cont_print_text(char *text, size_t size)
1744 return textlen; 1754 return textlen;
1745} 1755}
1746 1756
1757static size_t log_output(int facility, int level, enum log_flags lflags, const char *dict, size_t dictlen, char *text, size_t text_len)
1758{
1759 /*
1760 * If an earlier line was buffered, and we're a continuation
1761 * write from the same process, try to add it to the buffer.
1762 */
1763 if (cont.len) {
1764 if (cont.owner == current && (lflags & LOG_CONT)) {
1765 if (cont_add(facility, level, lflags, text, text_len))
1766 return text_len;
1767 }
1768 /* Otherwise, make sure it's flushed */
1769 cont_flush();
1770 }
1771
1772 /* If it doesn't end in a newline, try to buffer the current line */
1773 if (!(lflags & LOG_NEWLINE)) {
1774 if (cont_add(facility, level, lflags, text, text_len))
1775 return text_len;
1776 }
1777
1778 /* Store it in the record log */
1779 return log_store(facility, level, lflags, 0, dict, dictlen, text, text_len);
1780}
1781
1747asmlinkage int vprintk_emit(int facility, int level, 1782asmlinkage int vprintk_emit(int facility, int level,
1748 const char *dict, size_t dictlen, 1783 const char *dict, size_t dictlen,
1749 const char *fmt, va_list args) 1784 const char *fmt, va_list args)
@@ -1830,10 +1865,9 @@ asmlinkage int vprintk_emit(int facility, int level,
1830 1865
1831 /* strip kernel syslog prefix and extract log level or control flags */ 1866 /* strip kernel syslog prefix and extract log level or control flags */
1832 if (facility == 0) { 1867 if (facility == 0) {
1833 int kern_level = printk_get_level(text); 1868 int kern_level;
1834 1869
1835 if (kern_level) { 1870 while ((kern_level = printk_get_level(text)) != 0) {
1836 const char *end_of_header = printk_skip_level(text);
1837 switch (kern_level) { 1871 switch (kern_level) {
1838 case '0' ... '7': 1872 case '0' ... '7':
1839 if (level == LOGLEVEL_DEFAULT) 1873 if (level == LOGLEVEL_DEFAULT)
@@ -1841,14 +1875,13 @@ asmlinkage int vprintk_emit(int facility, int level,
1841 /* fallthrough */ 1875 /* fallthrough */
1842 case 'd': /* KERN_DEFAULT */ 1876 case 'd': /* KERN_DEFAULT */
1843 lflags |= LOG_PREFIX; 1877 lflags |= LOG_PREFIX;
1878 break;
1879 case 'c': /* KERN_CONT */
1880 lflags |= LOG_CONT;
1844 } 1881 }
1845 /* 1882
1846 * No need to check length here because vscnprintf 1883 text_len -= 2;
1847 * put '\0' at the end of the string. Only valid and 1884 text += 2;
1848 * newly printed level is detected.
1849 */
1850 text_len -= end_of_header - text;
1851 text = (char *)end_of_header;
1852 } 1885 }
1853 } 1886 }
1854 1887
@@ -1858,45 +1891,7 @@ asmlinkage int vprintk_emit(int facility, int level,
1858 if (dict) 1891 if (dict)
1859 lflags |= LOG_PREFIX|LOG_NEWLINE; 1892 lflags |= LOG_PREFIX|LOG_NEWLINE;
1860 1893
1861 if (!(lflags & LOG_NEWLINE)) { 1894 printed_len += log_output(facility, level, lflags, dict, dictlen, text, text_len);
1862 /*
1863 * Flush the conflicting buffer. An earlier newline was missing,
1864 * or another task also prints continuation lines.
1865 */
1866 if (cont.len && (lflags & LOG_PREFIX || cont.owner != current))
1867 cont_flush(LOG_NEWLINE);
1868
1869 /* buffer line if possible, otherwise store it right away */
1870 if (cont_add(facility, level, text, text_len))
1871 printed_len += text_len;
1872 else
1873 printed_len += log_store(facility, level,
1874 lflags | LOG_CONT, 0,
1875 dict, dictlen, text, text_len);
1876 } else {
1877 bool stored = false;
1878
1879 /*
1880 * If an earlier newline was missing and it was the same task,
1881 * either merge it with the current buffer and flush, or if
1882 * there was a race with interrupts (prefix == true) then just
1883 * flush it out and store this line separately.
1884 * If the preceding printk was from a different task and missed
1885 * a newline, flush and append the newline.
1886 */
1887 if (cont.len) {
1888 if (cont.owner == current && !(lflags & LOG_PREFIX))
1889 stored = cont_add(facility, level, text,
1890 text_len);
1891 cont_flush(LOG_NEWLINE);
1892 }
1893
1894 if (stored)
1895 printed_len += text_len;
1896 else
1897 printed_len += log_store(facility, level, lflags, 0,
1898 dict, dictlen, text, text_len);
1899 }
1900 1895
1901 logbuf_cpu = UINT_MAX; 1896 logbuf_cpu = UINT_MAX;
1902 raw_spin_unlock(&logbuf_lock); 1897 raw_spin_unlock(&logbuf_lock);
@@ -3040,6 +3035,7 @@ void kmsg_dump(enum kmsg_dump_reason reason)
3040 dumper->active = true; 3035 dumper->active = true;
3041 3036
3042 raw_spin_lock_irqsave(&logbuf_lock, flags); 3037 raw_spin_lock_irqsave(&logbuf_lock, flags);
3038 cont_flush();
3043 dumper->cur_seq = clear_seq; 3039 dumper->cur_seq = clear_seq;
3044 dumper->cur_idx = clear_idx; 3040 dumper->cur_idx = clear_idx;
3045 dumper->next_seq = log_next_seq; 3041 dumper->next_seq = log_next_seq;
@@ -3130,6 +3126,7 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
3130 bool ret; 3126 bool ret;
3131 3127
3132 raw_spin_lock_irqsave(&logbuf_lock, flags); 3128 raw_spin_lock_irqsave(&logbuf_lock, flags);
3129 cont_flush();
3133 ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len); 3130 ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len);
3134 raw_spin_unlock_irqrestore(&logbuf_lock, flags); 3131 raw_spin_unlock_irqrestore(&logbuf_lock, flags);
3135 3132
@@ -3172,6 +3169,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
3172 goto out; 3169 goto out;
3173 3170
3174 raw_spin_lock_irqsave(&logbuf_lock, flags); 3171 raw_spin_lock_irqsave(&logbuf_lock, flags);
3172 cont_flush();
3175 if (dumper->cur_seq < log_first_seq) { 3173 if (dumper->cur_seq < log_first_seq) {
3176 /* messages are gone, move to first available one */ 3174 /* messages are gone, move to first available one */
3177 dumper->cur_seq = log_first_seq; 3175 dumper->cur_seq = log_first_seq;
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index ace683838d80..d719db4219cd 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -527,9 +527,9 @@ static int policydb_index(struct policydb *p)
527 printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools", 527 printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools",
528 p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); 528 p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim);
529 if (p->mls_enabled) 529 if (p->mls_enabled)
530 printk(", %d sens, %d cats", p->p_levels.nprim, 530 printk(KERN_CONT ", %d sens, %d cats", p->p_levels.nprim,
531 p->p_cats.nprim); 531 p->p_cats.nprim);
532 printk("\n"); 532 printk(KERN_CONT "\n");
533 533
534 printk(KERN_DEBUG "SELinux: %d classes, %d rules\n", 534 printk(KERN_DEBUG "SELinux: %d classes, %d rules\n",
535 p->p_classes.nprim, p->te_avtab.nel); 535 p->p_classes.nprim, p->te_avtab.nel);