]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - kernel/printk/printk.c
Merge branches 'pm-core', 'pm-qos', 'pm-domains' and 'pm-opp'
[linux.git] / kernel / printk / printk.c
index f7a55e9ff2f7621c2403d6bf28c6f8b88d1120f2..4ba3d34938c033740b19ad27c74c01a8cdaef2b4 100644 (file)
@@ -46,7 +46,7 @@
 #include <linux/ctype.h>
 #include <linux/uio.h>
 
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <asm/sections.h>
 
 #define CREATE_TRACE_POINTS
@@ -356,7 +356,6 @@ DECLARE_WAIT_QUEUE_HEAD(log_wait);
 /* the next printk record to read by syslog(READ) or /proc/kmsg */
 static u64 syslog_seq;
 static u32 syslog_idx;
-static enum log_flags syslog_prev;
 static size_t syslog_partial;
 
 /* index and sequence number of the first record stored in the buffer */
@@ -370,7 +369,6 @@ static u32 log_next_idx;
 /* the next printk record to write to the console */
 static u64 console_seq;
 static u32 console_idx;
-static enum log_flags console_prev;
 
 /* the next printk record to read after the last 'clear' command */
 static u64 clear_seq;
@@ -639,27 +637,15 @@ static void append_char(char **pp, char *e, char c)
 }
 
 static ssize_t msg_print_ext_header(char *buf, size_t size,
-                                   struct printk_log *msg, u64 seq,
-                                   enum log_flags prev_flags)
+                                   struct printk_log *msg, u64 seq)
 {
        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)
-               cont = (prev_flags & LOG_CONT) ? '+' : 'c';
-
        return scnprintf(buf, size, "%u,%llu,%llu,%c;",
-                      (msg->facility << 3) | msg->level, seq, ts_usec, cont);
+                      (msg->facility << 3) | msg->level, seq, ts_usec,
+                      msg->flags & LOG_CONT ? 'c' : '-');
 }
 
 static ssize_t msg_print_ext_body(char *buf, size_t size,
@@ -714,7 +700,6 @@ static ssize_t msg_print_ext_body(char *buf, size_t size,
 struct devkmsg_user {
        u64 seq;
        u32 idx;
-       enum log_flags prev;
        struct ratelimit_state rs;
        struct mutex lock;
        char buf[CONSOLE_EXT_LOG_MAX];
@@ -748,7 +733,7 @@ static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from)
                return -ENOMEM;
 
        buf[len] = '\0';
-       if (copy_from_iter(buf, len, from) != len) {
+       if (!copy_from_iter_full(buf, len, from)) {
                kfree(buf);
                return -EFAULT;
        }
@@ -824,12 +809,11 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
 
        msg = log_from_idx(user->idx);
        len = msg_print_ext_header(user->buf, sizeof(user->buf),
-                                  msg, user->seq, user->prev);
+                                  msg, user->seq);
        len += msg_print_ext_body(user->buf + len, sizeof(user->buf) - len,
                                  log_dict(msg), msg->dict_len,
                                  log_text(msg), msg->text_len);
 
-       user->prev = msg->flags;
        user->idx = log_next(user->idx);
        user->seq++;
        raw_spin_unlock_irq(&logbuf_lock);
@@ -1210,26 +1194,12 @@ static size_t print_prefix(const struct printk_log *msg, bool syslog, char *buf)
        return len;
 }
 
-static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev,
-                            bool syslog, char *buf, size_t size)
+static size_t msg_print_text(const struct printk_log *msg, bool syslog, char *buf, size_t size)
 {
        const char *text = log_text(msg);
        size_t text_size = msg->text_len;
-       bool prefix = true;
-       bool newline = true;
        size_t len = 0;
 
-       if ((prev & LOG_CONT) && !(msg->flags & LOG_PREFIX))
-               prefix = false;
-
-       if (msg->flags & LOG_CONT) {
-               if ((prev & LOG_CONT) && !(prev & LOG_NEWLINE))
-                       prefix = false;
-
-               if (!(msg->flags & LOG_NEWLINE))
-                       newline = false;
-       }
-
        do {
                const char *next = memchr(text, '\n', text_size);
                size_t text_len;
@@ -1247,22 +1217,17 @@ static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev,
                            text_len + 1 >= size - len)
                                break;
 
-                       if (prefix)
-                               len += print_prefix(msg, syslog, buf + len);
+                       len += print_prefix(msg, syslog, buf + len);
                        memcpy(buf + len, text, text_len);
                        len += text_len;
-                       if (next || newline)
-                               buf[len++] = '\n';
+                       buf[len++] = '\n';
                } else {
                        /* SYSLOG_ACTION_* buffer size only calculation */
-                       if (prefix)
-                               len += print_prefix(msg, syslog, NULL);
+                       len += print_prefix(msg, syslog, NULL);
                        len += text_len;
-                       if (next || newline)
-                               len++;
+                       len++;
                }
 
-               prefix = true;
                text = next;
        } while (text);
 
@@ -1288,7 +1253,6 @@ static int syslog_print(char __user *buf, int size)
                        /* messages are gone, move to first one */
                        syslog_seq = log_first_seq;
                        syslog_idx = log_first_idx;
-                       syslog_prev = 0;
                        syslog_partial = 0;
                }
                if (syslog_seq == log_next_seq) {
@@ -1298,13 +1262,11 @@ static int syslog_print(char __user *buf, int size)
 
                skip = syslog_partial;
                msg = log_from_idx(syslog_idx);
-               n = msg_print_text(msg, syslog_prev, true, text,
-                                  LOG_LINE_MAX + PREFIX_MAX);
+               n = msg_print_text(msg, true, text, LOG_LINE_MAX + PREFIX_MAX);
                if (n - syslog_partial <= size) {
                        /* message fits into buffer, move forward */
                        syslog_idx = log_next(syslog_idx);
                        syslog_seq++;
-                       syslog_prev = msg->flags;
                        n -= syslog_partial;
                        syslog_partial = 0;
                } else if (!len){
@@ -1347,7 +1309,6 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                u64 next_seq;
                u64 seq;
                u32 idx;
-               enum log_flags prev;
 
                /*
                 * Find first record that fits, including all following records,
@@ -1355,12 +1316,10 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                 */
                seq = clear_seq;
                idx = clear_idx;
-               prev = 0;
                while (seq < log_next_seq) {
                        struct printk_log *msg = log_from_idx(idx);
 
-                       len += msg_print_text(msg, prev, true, NULL, 0);
-                       prev = msg->flags;
+                       len += msg_print_text(msg, true, NULL, 0);
                        idx = log_next(idx);
                        seq++;
                }
@@ -1368,12 +1327,10 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                /* move first record forward until length fits into the buffer */
                seq = clear_seq;
                idx = clear_idx;
-               prev = 0;
                while (len > size && seq < log_next_seq) {
                        struct printk_log *msg = log_from_idx(idx);
 
-                       len -= msg_print_text(msg, prev, true, NULL, 0);
-                       prev = msg->flags;
+                       len -= msg_print_text(msg, true, NULL, 0);
                        idx = log_next(idx);
                        seq++;
                }
@@ -1386,7 +1343,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                        struct printk_log *msg = log_from_idx(idx);
                        int textlen;
 
-                       textlen = msg_print_text(msg, prev, true, text,
+                       textlen = msg_print_text(msg, true, text,
                                                 LOG_LINE_MAX + PREFIX_MAX);
                        if (textlen < 0) {
                                len = textlen;
@@ -1394,7 +1351,6 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                        }
                        idx = log_next(idx);
                        seq++;
-                       prev = msg->flags;
 
                        raw_spin_unlock_irq(&logbuf_lock);
                        if (copy_to_user(buf + len, text, textlen))
@@ -1407,7 +1363,6 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                                /* messages are gone, move to next one */
                                seq = log_first_seq;
                                idx = log_first_idx;
-                               prev = 0;
                        }
                }
        }
@@ -1508,7 +1463,6 @@ int do_syslog(int type, char __user *buf, int len, int source)
                        /* messages are gone, move to first one */
                        syslog_seq = log_first_seq;
                        syslog_idx = log_first_idx;
-                       syslog_prev = 0;
                        syslog_partial = 0;
                }
                if (source == SYSLOG_FROM_PROC) {
@@ -1521,16 +1475,14 @@ int do_syslog(int type, char __user *buf, int len, int source)
                } else {
                        u64 seq = syslog_seq;
                        u32 idx = syslog_idx;
-                       enum log_flags prev = syslog_prev;
 
                        error = 0;
                        while (seq < log_next_seq) {
                                struct printk_log *msg = log_from_idx(idx);
 
-                               error += msg_print_text(msg, prev, true, NULL, 0);
+                               error += msg_print_text(msg, true, NULL, 0);
                                idx = log_next(idx);
                                seq++;
-                               prev = msg->flags;
                        }
                        error -= syslog_partial;
                }
@@ -1564,7 +1516,7 @@ static void call_console_drivers(int level,
 {
        struct console *con;
 
-       trace_console(text, len);
+       trace_console_rcuidle(text, len);
 
        if (!console_drivers)
                return;
@@ -1631,46 +1583,25 @@ static inline void printk_delay(void)
 static struct cont {
        char buf[LOG_LINE_MAX];
        size_t len;                     /* length == 0 means unused buffer */
-       size_t cons;                    /* bytes written to console */
        struct task_struct *owner;      /* task of first print*/
        u64 ts_nsec;                    /* time of first print */
        u8 level;                       /* log level of first message */
        u8 facility;                    /* log facility of first message */
        enum log_flags flags;           /* prefix, newline flags */
-       bool flushed:1;                 /* buffer sealed and committed */
 } cont;
 
 static void cont_flush(void)
 {
-       if (cont.flushed)
-               return;
        if (cont.len == 0)
                return;
-       if (cont.cons) {
-               /*
-                * If a fragment of this line was directly flushed to the
-                * console; wait for the console to pick up the rest of the
-                * line. LOG_NOCONS suppresses a duplicated output.
-                */
-               log_store(cont.facility, cont.level, cont.flags | LOG_NOCONS,
-                         cont.ts_nsec, NULL, 0, cont.buf, cont.len);
-               cont.flushed = true;
-       } else {
-               /*
-                * If no fragment of this line ever reached the console,
-                * just submit it to the store and free the buffer.
-                */
-               log_store(cont.facility, cont.level, cont.flags, 0,
-                         NULL, 0, cont.buf, cont.len);
-               cont.len = 0;
-       }
+
+       log_store(cont.facility, cont.level, cont.flags, cont.ts_nsec,
+                 NULL, 0, cont.buf, cont.len);
+       cont.len = 0;
 }
 
 static bool cont_add(int facility, int level, enum log_flags flags, const char *text, size_t len)
 {
-       if (cont.len && cont.flushed)
-               return false;
-
        /*
         * If ext consoles are present, flush and skip in-kernel
         * continuation.  See nr_ext_console_drivers definition.  Also, if
@@ -1687,8 +1618,6 @@ static bool cont_add(int facility, int level, enum log_flags flags, const char *
                cont.owner = current;
                cont.ts_nsec = local_clock();
                cont.flags = flags;
-               cont.cons = 0;
-               cont.flushed = false;
        }
 
        memcpy(cont.buf + cont.len, text, len);
@@ -1707,34 +1636,6 @@ static bool cont_add(int facility, int level, enum log_flags flags, const char *
        return true;
 }
 
-static size_t cont_print_text(char *text, size_t size)
-{
-       size_t textlen = 0;
-       size_t len;
-
-       if (cont.cons == 0 && (console_prev & LOG_NEWLINE)) {
-               textlen += print_time(cont.ts_nsec, text);
-               size -= textlen;
-       }
-
-       len = cont.len - cont.cons;
-       if (len > 0) {
-               if (len+1 > size)
-                       len = size-1;
-               memcpy(text + textlen, cont.buf + cont.cons, len);
-               textlen += len;
-               cont.cons = cont.len;
-       }
-
-       if (cont.flushed) {
-               if (cont.flags & LOG_NEWLINE)
-                       text[textlen++] = '\n';
-               /* got everything, release buffer */
-               cont.len = 0;
-       }
-       return textlen;
-}
-
 static size_t log_output(int facility, int level, enum log_flags lflags, const char *dict, size_t dictlen, char *text, size_t text_len)
 {
        /*
@@ -1926,7 +1827,8 @@ int vprintk_default(const char *fmt, va_list args)
        int r;
 
 #ifdef CONFIG_KGDB_KDB
-       if (unlikely(kdb_trap_printk)) {
+       /* Allow to pass printk() to kdb but avoid a recursion. */
+       if (unlikely(kdb_trap_printk && kdb_printf_cpu < 0)) {
                r = vkdb_printf(KDB_MSGSRC_PRINTK, fmt, args);
                return r;
        }
@@ -1980,33 +1882,24 @@ static u64 syslog_seq;
 static u32 syslog_idx;
 static u64 console_seq;
 static u32 console_idx;
-static enum log_flags syslog_prev;
 static u64 log_first_seq;
 static u32 log_first_idx;
 static u64 log_next_seq;
-static enum log_flags console_prev;
-static struct cont {
-       size_t len;
-       size_t cons;
-       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 ssize_t msg_print_ext_header(char *buf, size_t size,
-                                   struct printk_log *msg, u64 seq,
-                                   enum log_flags prev_flags) { return 0; }
+                                   struct printk_log *msg,
+                                   u64 seq) { 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,
+static size_t msg_print_text(const struct printk_log *msg,
                             bool syslog, char *buf, size_t size) { return 0; }
-static size_t cont_print_text(char *text, size_t size) { return 0; }
 static bool suppress_message_printing(int level) { return false; }
 
 /* Still needs to be defined for users */
@@ -2166,27 +2059,20 @@ void resume_console(void)
 
 /**
  * console_cpu_notify - print deferred console messages after CPU hotplug
- * @self: notifier struct
- * @action: CPU hotplug event
- * @hcpu: unused
+ * @cpu: unused
  *
  * If printk() is called from a CPU that is not online yet, the messages
  * will be spooled but will not show up on the console.  This function is
  * called when a new CPU comes online (or fails to come up), and ensures
  * that any such output gets printed.
  */
-static int console_cpu_notify(struct notifier_block *self,
-       unsigned long action, void *hcpu)
-{
-       switch (action) {
-       case CPU_ONLINE:
-       case CPU_DEAD:
-       case CPU_DOWN_FAILED:
-       case CPU_UP_CANCELED:
+static int console_cpu_notify(unsigned int cpu)
+{
+       if (!cpuhp_tasks_frozen) {
                console_lock();
                console_unlock();
        }
-       return NOTIFY_OK;
+       return 0;
 }
 
 /**
@@ -2277,42 +2163,6 @@ static inline int can_use_console(void)
        return cpu_online(raw_smp_processor_id()) || have_callable_console();
 }
 
-static void console_cont_flush(char *text, size_t size)
-{
-       unsigned long flags;
-       size_t len;
-
-       raw_spin_lock_irqsave(&logbuf_lock, flags);
-
-       if (!cont.len)
-               goto out;
-
-       if (suppress_message_printing(cont.level)) {
-               cont.cons = cont.len;
-               if (cont.flushed)
-                       cont.len = 0;
-               goto out;
-       }
-
-       /*
-        * We still queue earlier records, likely because the console was
-        * busy. The earlier ones need to be printed before this one, we
-        * did not flush any fragment so far, so just let it queue up.
-        */
-       if (console_seq < log_next_seq && !cont.cons)
-               goto out;
-
-       len = cont_print_text(text, size);
-       raw_spin_unlock(&logbuf_lock);
-       stop_critical_timings();
-       call_console_drivers(cont.level, NULL, 0, text, len);
-       start_critical_timings();
-       local_irq_restore(flags);
-       return;
-out:
-       raw_spin_unlock_irqrestore(&logbuf_lock, flags);
-}
-
 /**
  * console_unlock - unlock the console system
  *
@@ -2366,9 +2216,6 @@ void console_unlock(void)
                return;
        }
 
-       /* flush buffered message fragment immediately to console */
-       console_cont_flush(text, sizeof(text));
-
        for (;;) {
                struct printk_log *msg;
                size_t ext_len = 0;
@@ -2388,7 +2235,6 @@ void console_unlock(void)
                        /* messages are gone, move to first one */
                        console_seq = log_first_seq;
                        console_idx = log_first_idx;
-                       console_prev = 0;
                } else {
                        len = 0;
                }
@@ -2398,8 +2244,7 @@ void console_unlock(void)
 
                msg = log_from_idx(console_idx);
                level = msg->level;
-               if ((msg->flags & LOG_NOCONS) ||
-                               suppress_message_printing(level)) {
+               if (suppress_message_printing(level)) {
                        /*
                         * Skip record we have buffered and already printed
                         * directly to the console when we received it, and
@@ -2407,22 +2252,14 @@ void console_unlock(void)
                         */
                        console_idx = log_next(console_idx);
                        console_seq++;
-                       /*
-                        * We will get here again when we register a new
-                        * CON_PRINTBUFFER console. Clear the flag so we
-                        * will properly dump everything later.
-                        */
-                       msg->flags &= ~LOG_NOCONS;
-                       console_prev = msg->flags;
                        goto skip;
                }
 
-               len += msg_print_text(msg, console_prev, false,
-                                     text + len, sizeof(text) - len);
+               len += msg_print_text(msg, 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);
+                                               msg, console_seq);
                        ext_len += msg_print_ext_body(ext_text + ext_len,
                                                sizeof(ext_text) - ext_len,
                                                log_dict(msg), msg->dict_len,
@@ -2430,7 +2267,6 @@ void console_unlock(void)
                }
                console_idx = log_next(console_idx);
                console_seq++;
-               console_prev = msg->flags;
                raw_spin_unlock(&logbuf_lock);
 
                stop_critical_timings();        /* don't trace print latency */
@@ -2725,7 +2561,6 @@ void register_console(struct console *newcon)
                raw_spin_lock_irqsave(&logbuf_lock, flags);
                console_seq = syslog_seq;
                console_idx = syslog_idx;
-               console_prev = syslog_prev;
                raw_spin_unlock_irqrestore(&logbuf_lock, flags);
                /*
                 * We're about to replay the log buffer.  Only do this to the
@@ -2824,6 +2659,7 @@ EXPORT_SYMBOL(unregister_console);
 static int __init printk_late_init(void)
 {
        struct console *con;
+       int ret;
 
        for_each_console(con) {
                if (!keep_bootcon && con->flags & CON_BOOT) {
@@ -2838,7 +2674,12 @@ static int __init printk_late_init(void)
                                unregister_console(con);
                }
        }
-       hotcpu_notifier(console_cpu_notify, 0);
+       ret = cpuhp_setup_state_nocalls(CPUHP_PRINTK_DEAD, "printk:dead", NULL,
+                                       console_cpu_notify);
+       WARN_ON(ret < 0);
+       ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "printk:online",
+                                       console_cpu_notify, NULL);
+       WARN_ON(ret < 0);
        return 0;
 }
 late_initcall(printk_late_init);
@@ -3075,7 +2916,7 @@ bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog,
                goto out;
 
        msg = log_from_idx(dumper->cur_idx);
-       l = msg_print_text(msg, 0, syslog, line, size);
+       l = msg_print_text(msg, syslog, line, size);
 
        dumper->cur_idx = log_next(dumper->cur_idx);
        dumper->cur_seq++;
@@ -3144,7 +2985,6 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        u32 idx;
        u64 next_seq;
        u32 next_idx;
-       enum log_flags prev;
        size_t l = 0;
        bool ret = false;
 
@@ -3167,27 +3007,23 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        /* calculate length of entire buffer */
        seq = dumper->cur_seq;
        idx = dumper->cur_idx;
-       prev = 0;
        while (seq < dumper->next_seq) {
                struct printk_log *msg = log_from_idx(idx);
 
-               l += msg_print_text(msg, prev, true, NULL, 0);
+               l += msg_print_text(msg, true, NULL, 0);
                idx = log_next(idx);
                seq++;
-               prev = msg->flags;
        }
 
        /* move first record forward until length fits into the buffer */
        seq = dumper->cur_seq;
        idx = dumper->cur_idx;
-       prev = 0;
        while (l > size && seq < dumper->next_seq) {
                struct printk_log *msg = log_from_idx(idx);
 
-               l -= msg_print_text(msg, prev, true, NULL, 0);
+               l -= msg_print_text(msg, true, NULL, 0);
                idx = log_next(idx);
                seq++;
-               prev = msg->flags;
        }
 
        /* last message in next interation */
@@ -3198,10 +3034,9 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        while (seq < dumper->next_seq) {
                struct printk_log *msg = log_from_idx(idx);
 
-               l += msg_print_text(msg, prev, syslog, buf + l, size - l);
+               l += msg_print_text(msg, syslog, buf + l, size - l);
                idx = log_next(idx);
                seq++;
-               prev = msg->flags;
        }
 
        dumper->next_seq = next_seq;