printk: remove console flushing special cases for partial buffered lines
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 25 Oct 2016 18:27:31 +0000 (11:27 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 15 Dec 2016 05:08:18 +0000 (21:08 -0800)
It actively hurts proper merging, and makes for a lot of special cases.
There was a good(ish) reason for doing it originally, but it's getting
too painful to maintain.  And most of the original reasons for it are
long gone.

So instead of having special code to flush partial lines to the console
(as opposed to the record buffers), do _all_ the console writing from
the record buffer, and be done with it.

If an oops happens (or some other synchronous event), we will flush the
partial lines due to the oops printing activity, so this does not affect
that.  It does mean that if you have a completely hung machine, a
partial preceding line may not have been printed out.

That was some of the original reason for this complexity, in fact, back
when we used to test for the historical i386 "halt" instruction problem
by doing

pr_info("Checking 'hlt' instruction... ");

if (!boot_cpu_data.hlt_works_ok) {
pr_cont("disabled\n");
return;
}
halt();
halt();
halt();
halt();
pr_cont("OK\n");

and that model no longer works (it the 'hlt' instruction kills the
machine, the partial line won't have been flushed, so you won't even see
it).

Of course, that was also back in the days when people actually had
textual console output rather than a graphical splash-screen at bootup.
How times change..

Cc: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
Cc: Joe Perches <joe@perches.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Tested-by: Petr Mladek <pmladek@suse.com>
Tested-by: Geert Uytterhoeven <geert@linux-m68k.org>
Tested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
kernel/printk/printk.c

index 50b2703d6d6a76a41f6a8f6705b7b0eaff0785a8..b3c454b733da8163f2616eb5bc9579ea40e697a8 100644 (file)
@@ -1583,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
@@ -1639,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);
@@ -1659,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) {
-               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)
 {
        /*
@@ -1957,7 +1906,6 @@ static void call_console_drivers(int level,
                                 const char *text, size_t len) {}
 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 */
@@ -2221,42 +2169,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
  *
@@ -2310,9 +2222,6 @@ again:
                return;
        }
 
-       /* flush buffered message fragment immediately to console */
-       console_cont_flush(text, sizeof(text));
-
        for (;;) {
                struct printk_log *msg;
                size_t ext_len = 0;
@@ -2341,8 +2250,7 @@ skip:
 
                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
@@ -2350,12 +2258,6 @@ skip:
                         */
                        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;
                        goto skip;
                }