These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / kernel / printk / printk.c
index c2d5877..f75e4b0 100644 (file)
@@ -84,6 +84,18 @@ static struct lockdep_map console_lock_dep_map = {
 };
 #endif
 
+/*
+ * Number of registered extended console drivers.
+ *
+ * If extended consoles are present, in-kernel cont reassembly is disabled
+ * and each fragment is stored as a separate log entry with proper
+ * continuation flag so that every emitted message has full metadata.  This
+ * doesn't change the result for regular consoles or /proc/kmsg.  For
+ * /dev/kmsg, as long as the reader concatenates messages according to
+ * consecutive continuation flags, the end result should be the same too.
+ */
+static int nr_ext_console_drivers;
+
 /*
  * Helper macros to handle lockdep when locking/unlocking console_sem. We use
  * macros instead of functions so that _RET_IP_ contains useful information.
@@ -195,14 +207,14 @@ static int console_may_schedule;
  * need to be changed in the future, when the requirements change.
  *
  * /dev/kmsg exports the structured data in the following line format:
- *   "level,sequnum,timestamp;<message text>\n"
+ *   "<level>,<sequnum>,<timestamp>,<contflag>[,additional_values, ... ];<message text>\n"
+ *
+ * Users of the export format should ignore possible additional values
+ * separated by ',', and find the message after the ';' character.
  *
  * The optional key/value pairs are attached as continuation lines starting
  * with a space character and terminated by a newline. All possible
  * non-prinatable characters are escaped in the "\xff" notation.
- *
- * Users of the export format should ignore possible additional values
- * separated by ',', and find the message after the ';' character.
  */
 
 enum log_flags {
@@ -229,6 +241,65 @@ struct printk_log {
  */
 static DEFINE_RAW_SPINLOCK(logbuf_lock);
 
+#ifdef CONFIG_EARLY_PRINTK
+struct console *early_console;
+
+static void early_vprintk(const char *fmt, va_list ap)
+{
+       if (early_console) {
+               char buf[512];
+               int n = vscnprintf(buf, sizeof(buf), fmt, ap);
+
+               early_console->write(early_console, buf, n);
+       }
+}
+
+asmlinkage void early_printk(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       early_vprintk(fmt, ap);
+       va_end(ap);
+}
+
+/*
+ * This is independent of any log levels - a global
+ * kill switch that turns off all of printk.
+ *
+ * Used by the NMI watchdog if early-printk is enabled.
+ */
+static bool __read_mostly printk_killswitch;
+
+static int __init force_early_printk_setup(char *str)
+{
+       printk_killswitch = true;
+       return 0;
+}
+early_param("force_early_printk", force_early_printk_setup);
+
+void printk_kill(void)
+{
+       printk_killswitch = true;
+}
+
+#ifdef CONFIG_PRINTK
+static int forced_early_printk(const char *fmt, va_list ap)
+{
+       if (!printk_killswitch)
+               return 0;
+       early_vprintk(fmt, ap);
+       return 1;
+}
+#endif
+
+#else
+static inline int forced_early_printk(const char *fmt, va_list ap)
+{
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_PRINTK
 DECLARE_WAIT_QUEUE_HEAD(log_wait);
 /* the next printk record to read by syslog(READ) or /proc/kmsg */
@@ -257,6 +328,9 @@ static u32 clear_idx;
 #define PREFIX_MAX             32
 #define LOG_LINE_MAX           (1024 - PREFIX_MAX)
 
+#define LOG_LEVEL(v)           ((v) & 0x07)
+#define LOG_FACILITY(v)                ((v) >> 3 & 0xff)
+
 /* record buffer */
 #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
 #define LOG_ALIGN 4
@@ -477,13 +551,13 @@ static int syslog_action_restricted(int type)
               type != SYSLOG_ACTION_SIZE_BUFFER;
 }
 
-int check_syslog_permissions(int type, bool from_file)
+int check_syslog_permissions(int type, int source)
 {
        /*
         * If this is from /proc/kmsg and we've already opened it, then we've
         * already done the capabilities checks at open time.
         */
-       if (from_file && type != SYSLOG_ACTION_OPEN)
+       if (source == SYSLOG_FROM_PROC && type != SYSLOG_ACTION_OPEN)
                goto ok;
 
        if (syslog_action_restricted(type)) {
@@ -505,7 +579,88 @@ int check_syslog_permissions(int type, bool from_file)
 ok:
        return security_syslog(type);
 }
+EXPORT_SYMBOL_GPL(check_syslog_permissions);
+
+static void append_char(char **pp, char *e, char c)
+{
+       if (*pp < e)
+               *(*pp)++ = c;
+}
 
+static ssize_t msg_print_ext_header(char *buf, size_t size,
+                                   struct printk_log *msg, u64 seq,
+                                   enum log_flags prev_flags)
+{
+       u64 ts_usec = msg->ts_nsec;
+       char cont = '-';
+
+       do_div(ts_usec, 1000);
+
+       /*
+        * If we couldn't merge continuation line fragments during the print,
+        * export the stored flags to allow an optional external merge of the
+        * records. Merging the records isn't always neccessarily correct, like
+        * when we hit a race during printing. In most cases though, it produces
+        * better readable output. 'c' in the record flags mark the first
+        * fragment of a line, '+' the following.
+        */
+       if (msg->flags & LOG_CONT && !(prev_flags & LOG_CONT))
+               cont = 'c';
+       else if ((msg->flags & LOG_CONT) ||
+                ((prev_flags & LOG_CONT) && !(msg->flags & LOG_PREFIX)))
+               cont = '+';
+
+       return scnprintf(buf, size, "%u,%llu,%llu,%c;",
+                      (msg->facility << 3) | msg->level, seq, ts_usec, cont);
+}
+
+static ssize_t msg_print_ext_body(char *buf, size_t size,
+                                 char *dict, size_t dict_len,
+                                 char *text, size_t text_len)
+{
+       char *p = buf, *e = buf + size;
+       size_t i;
+
+       /* escape non-printable characters */
+       for (i = 0; i < text_len; i++) {
+               unsigned char c = text[i];
+
+               if (c < ' ' || c >= 127 || c == '\\')
+                       p += scnprintf(p, e - p, "\\x%02x", c);
+               else
+                       append_char(&p, e, c);
+       }
+       append_char(&p, e, '\n');
+
+       if (dict_len) {
+               bool line = true;
+
+               for (i = 0; i < dict_len; i++) {
+                       unsigned char c = dict[i];
+
+                       if (line) {
+                               append_char(&p, e, ' ');
+                               line = false;
+                       }
+
+                       if (c == '\0') {
+                               append_char(&p, e, '\n');
+                               line = true;
+                               continue;
+                       }
+
+                       if (c < ' ' || c >= 127 || c == '\\') {
+                               p += scnprintf(p, e - p, "\\x%02x", c);
+                               continue;
+                       }
+
+                       append_char(&p, e, c);
+               }
+               append_char(&p, e, '\n');
+       }
+
+       return p - buf;
+}
 
 /* /dev/kmsg - userspace message inject/listen interface */
 struct devkmsg_user {
@@ -513,13 +668,12 @@ struct devkmsg_user {
        u32 idx;
        enum log_flags prev;
        struct mutex lock;
-       char buf[8192];
+       char buf[CONSOLE_EXT_LOG_MAX];
 };
 
 static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from)
 {
        char *buf, *line;
-       int i;
        int level = default_message_loglevel;
        int facility = 1;       /* LOG_USER */
        size_t len = iov_iter_count(from);
@@ -549,12 +703,13 @@ static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from)
        line = buf;
        if (line[0] == '<') {
                char *endp = NULL;
+               unsigned int u;
 
-               i = simple_strtoul(line+1, &endp, 10);
+               u = simple_strtoul(line + 1, &endp, 10);
                if (endp && endp[0] == '>') {
-                       level = i & 7;
-                       if (i >> 3)
-                               facility = i >> 3;
+                       level = LOG_LEVEL(u);
+                       if (LOG_FACILITY(u) != 0)
+                               facility = LOG_FACILITY(u);
                        endp++;
                        len -= endp - line;
                        line = endp;
@@ -571,9 +726,6 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
 {
        struct devkmsg_user *user = file->private_data;
        struct printk_log *msg;
-       u64 ts_usec;
-       size_t i;
-       char cont = '-';
        size_t len;
        ssize_t ret;
 
@@ -609,66 +761,13 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
        }
 
        msg = log_from_idx(user->idx);
-       ts_usec = msg->ts_nsec;
-       do_div(ts_usec, 1000);
-
-       /*
-        * If we couldn't merge continuation line fragments during the print,
-        * export the stored flags to allow an optional external merge of the
-        * records. Merging the records isn't always neccessarily correct, like
-        * when we hit a race during printing. In most cases though, it produces
-        * better readable output. 'c' in the record flags mark the first
-        * fragment of a line, '+' the following.
-        */
-       if (msg->flags & LOG_CONT && !(user->prev & LOG_CONT))
-               cont = 'c';
-       else if ((msg->flags & LOG_CONT) ||
-                ((user->prev & LOG_CONT) && !(msg->flags & LOG_PREFIX)))
-               cont = '+';
+       len = msg_print_ext_header(user->buf, sizeof(user->buf),
+                                  msg, user->seq, user->prev);
+       len += msg_print_ext_body(user->buf + len, sizeof(user->buf) - len,
+                                 log_dict(msg), msg->dict_len,
+                                 log_text(msg), msg->text_len);
 
-       len = sprintf(user->buf, "%u,%llu,%llu,%c;",
-                     (msg->facility << 3) | msg->level,
-                     user->seq, ts_usec, cont);
        user->prev = msg->flags;
-
-       /* escape non-printable characters */
-       for (i = 0; i < msg->text_len; i++) {
-               unsigned char c = log_text(msg)[i];
-
-               if (c < ' ' || c >= 127 || c == '\\')
-                       len += sprintf(user->buf + len, "\\x%02x", c);
-               else
-                       user->buf[len++] = c;
-       }
-       user->buf[len++] = '\n';
-
-       if (msg->dict_len) {
-               bool line = true;
-
-               for (i = 0; i < msg->dict_len; i++) {
-                       unsigned char c = log_dict(msg)[i];
-
-                       if (line) {
-                               user->buf[len++] = ' ';
-                               line = false;
-                       }
-
-                       if (c == '\0') {
-                               user->buf[len++] = '\n';
-                               line = true;
-                               continue;
-                       }
-
-                       if (c < ' ' || c >= 127 || c == '\\') {
-                               len += sprintf(user->buf + len, "\\x%02x", c);
-                               continue;
-                       }
-
-                       user->buf[len++] = c;
-               }
-               user->buf[len++] = '\n';
-       }
-
        user->idx = log_next(user->idx);
        user->seq++;
        raw_spin_unlock_irq(&logbuf_lock);
@@ -799,7 +898,7 @@ const struct file_operations kmsg_fops = {
        .release = devkmsg_release,
 };
 
-#ifdef CONFIG_KEXEC
+#ifdef CONFIG_KEXEC_CORE
 /*
  * This appends the listed symbols to /proc/vmcore
  *
@@ -1279,13 +1378,13 @@ out:
        return len;
 }
 
-int do_syslog(int type, char __user *buf, int len, bool from_file)
+int do_syslog(int type, char __user *buf, int len, int source)
 {
        bool clear = false;
        static int saved_console_loglevel = LOGLEVEL_DEFAULT;
        int error;
 
-       error = check_syslog_permissions(type, from_file);
+       error = check_syslog_permissions(type, source);
        if (error)
                goto out;
 
@@ -1368,7 +1467,7 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
                        syslog_prev = 0;
                        syslog_partial = 0;
                }
-               if (from_file) {
+               if (source == SYSLOG_FROM_PROC) {
                        /*
                         * Short-cut for poll(/"proc/kmsg") which simply checks
                         * for pending data, not the size; return the count of
@@ -1415,7 +1514,9 @@ SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
  * log_buf[start] to log_buf[end - 1].
  * The console_lock must be held.
  */
-static void call_console_drivers(int level, const char *text, size_t len)
+static void call_console_drivers(int level,
+                                const char *ext_text, size_t ext_len,
+                                const char *text, size_t len)
 {
        struct console *con;
 
@@ -1437,7 +1538,10 @@ static void call_console_drivers(int level, const char *text, size_t len)
                if (!cpu_online(smp_processor_id()) &&
                    !(con->flags & CON_ANYTIME))
                        continue;
-               con->write(con, text, len);
+               if (con->flags & CON_EXTENDED)
+                       con->write(con, ext_text, ext_len);
+               else
+                       con->write(con, text, len);
        }
        migrate_enable();
 }
@@ -1590,8 +1694,12 @@ static bool cont_add(int facility, int level, const char *text, size_t len)
        if (cont.len && cont.flushed)
                return false;
 
-       if (cont.len + len > sizeof(cont.buf)) {
-               /* the line gets too long, split it up in separate records */
+       /*
+        * If ext consoles are present, flush and skip in-kernel
+        * continuation.  See nr_ext_console_drivers definition.  Also, if
+        * the line gets too long, split it up in separate records.
+        */
+       if (nr_ext_console_drivers || cont.len + len > sizeof(cont.buf)) {
                cont_flush(LOG_CONT);
                return false;
        }
@@ -1643,62 +1751,6 @@ static size_t cont_print_text(char *text, size_t size)
        return textlen;
 }
 
-#ifdef CONFIG_EARLY_PRINTK
-struct console *early_console;
-
-static void early_vprintk(const char *fmt, va_list ap)
-{
-       if (early_console) {
-               char buf[512];
-               int n = vscnprintf(buf, sizeof(buf), fmt, ap);
-
-               early_console->write(early_console, buf, n);
-       }
-}
-
-asmlinkage void early_printk(const char *fmt, ...)
-{
-       va_list ap;
-
-       va_start(ap, fmt);
-       early_vprintk(fmt, ap);
-       va_end(ap);
-}
-
-/*
- * This is independent of any log levels - a global
- * kill switch that turns off all of printk.
- *
- * Used by the NMI watchdog if early-printk is enabled.
- */
-static bool __read_mostly printk_killswitch;
-
-static int __init force_early_printk_setup(char *str)
-{
-       printk_killswitch = true;
-       return 0;
-}
-early_param("force_early_printk", force_early_printk_setup);
-
-void printk_kill(void)
-{
-       printk_killswitch = true;
-}
-
-static int forced_early_printk(const char *fmt, va_list ap)
-{
-       if (!printk_killswitch)
-               return 0;
-       early_vprintk(fmt, ap);
-       return 1;
-}
-#else
-static inline int forced_early_printk(const char *fmt, va_list ap)
-{
-       return 0;
-}
-#endif
-
 asmlinkage int vprintk_emit(int facility, int level,
                            const char *dict, size_t dictlen,
                            const char *fmt, va_list args)
@@ -1988,9 +2040,19 @@ static struct cont {
        u8 level;
        bool flushed:1;
 } cont;
+static char *log_text(const struct printk_log *msg) { return NULL; }
+static char *log_dict(const struct printk_log *msg) { return NULL; }
 static struct printk_log *log_from_idx(u32 idx) { return NULL; }
 static u32 log_next(u32 idx) { return 0; }
-static void call_console_drivers(int level, const char *text, size_t len) {}
+static ssize_t msg_print_ext_header(char *buf, size_t size,
+                                   struct printk_log *msg, u64 seq,
+                                   enum log_flags prev_flags) { return 0; }
+static ssize_t msg_print_ext_body(char *buf, size_t size,
+                                 char *dict, size_t dict_len,
+                                 char *text, size_t text_len) { return 0; }
+static void call_console_drivers(int level,
+                                const char *ext_text, size_t ext_len,
+                                const char *text, size_t len) {}
 static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev,
                             bool syslog, char *buf, size_t size) { return 0; }
 static size_t cont_print_text(char *text, size_t size) { return 0; }
@@ -2221,15 +2283,15 @@ static void console_cont_flush(char *text, size_t size)
                goto out;
 
        len = cont_print_text(text, size);
-#ifndef CONFIG_PREEMPT_RT_FULL
+#ifdef CONFIG_PREEMPT_RT_FULL
+       raw_spin_unlock_irqrestore(&logbuf_lock, flags);
+       call_console_drivers(cont.level, NULL, 0, text, len);
+#else
        raw_spin_unlock(&logbuf_lock);
        stop_critical_timings();
-       call_console_drivers(cont.level, text, len);
+       call_console_drivers(cont.level, NULL, 0, text, len);
        start_critical_timings();
        local_irq_restore(flags);
-#else
-       raw_spin_unlock_irqrestore(&logbuf_lock, flags);
-       call_console_drivers(cont.level, text, len);
 #endif
        return;
 out:
@@ -2252,17 +2314,29 @@ out:
  */
 void console_unlock(void)
 {
+       static char ext_text[CONSOLE_EXT_LOG_MAX];
        static char text[LOG_LINE_MAX + PREFIX_MAX];
        static u64 seen_seq;
        unsigned long flags;
        bool wake_klogd = false;
-       bool retry;
+       bool do_cond_resched, retry;
 
        if (console_suspended) {
                up_console_sem();
                return;
        }
 
+       /*
+        * Console drivers are called under logbuf_lock, so
+        * @console_may_schedule should be cleared before; however, we may
+        * end up dumping a lot of lines, for example, if called from
+        * console registration path, and should invoke cond_resched()
+        * between lines if allowable.  Not doing so can cause a very long
+        * scheduling stall on a slow console leading to RCU stall and
+        * softlockup warnings which exacerbate the issue with more
+        * messages practically incapacitating the system.
+        */
+       do_cond_resched = console_may_schedule;
        console_may_schedule = 0;
 
        /* flush buffered message fragment immediately to console */
@@ -2270,6 +2344,7 @@ void console_unlock(void)
 again:
        for (;;) {
                struct printk_log *msg;
+               size_t ext_len = 0;
                size_t len;
                int level;
 
@@ -2315,20 +2390,31 @@ skip:
                level = msg->level;
                len += msg_print_text(msg, console_prev, false,
                                      text + len, sizeof(text) - len);
+               if (nr_ext_console_drivers) {
+                       ext_len = msg_print_ext_header(ext_text,
+                                               sizeof(ext_text),
+                                               msg, console_seq, console_prev);
+                       ext_len += msg_print_ext_body(ext_text + ext_len,
+                                               sizeof(ext_text) - ext_len,
+                                               log_dict(msg), msg->dict_len,
+                                               log_text(msg), msg->text_len);
+               }
                console_idx = log_next(console_idx);
                console_seq++;
                console_prev = msg->flags;
 #ifdef CONFIG_PREEMPT_RT_FULL
                raw_spin_unlock_irqrestore(&logbuf_lock, flags);
-               call_console_drivers(level, text, len);
+               call_console_drivers(level, ext_text, ext_len, text, len);
 #else
                raw_spin_unlock(&logbuf_lock);
 
                stop_critical_timings();        /* don't trace print latency */
-               call_console_drivers(level, text, len);
+               call_console_drivers(level, ext_text, ext_len, text, len);
                start_critical_timings();
                local_irq_restore(flags);
 #endif
+               if (do_cond_resched)
+                       cond_resched();
        }
        console_locked = 0;
 
@@ -2396,6 +2482,25 @@ void console_unblank(void)
        console_unlock();
 }
 
+/**
+ * console_flush_on_panic - flush console content on panic
+ *
+ * Immediately output all pending messages no matter what.
+ */
+void console_flush_on_panic(void)
+{
+       /*
+        * If someone else is holding the console lock, trylock will fail
+        * and may_schedule may be set.  Ignore and proceed to unlock so
+        * that messages are flushed out.  As this can be called from any
+        * context and we don't want to get preempted while flushing,
+        * ensure may_schedule is cleared.
+        */
+       console_trylock();
+       console_may_schedule = 0;
+       console_unlock();
+}
+
 /*
  * Return the console tty driver structure and its associated index
  */
@@ -2582,6 +2687,11 @@ void register_console(struct console *newcon)
                newcon->next = console_drivers->next;
                console_drivers->next = newcon;
        }
+
+       if (newcon->flags & CON_EXTENDED)
+               if (!nr_ext_console_drivers++)
+                       pr_info("printk: continuation disabled due to ext consoles, expect more fragments in /dev/kmsg\n");
+
        if (newcon->flags & CON_PRINTBUFFER) {
                /*
                 * console_unlock(); will print out the buffered messages
@@ -2654,6 +2764,9 @@ int unregister_console(struct console *console)
                }
        }
 
+       if (!res && (console->flags & CON_EXTENDED))
+               nr_ext_console_drivers--;
+
        /*
         * If this isn't the last console and it has CON_CONSDEV set, we
         * need to set it on the next preferred console.