static u64 log_next_seq;
 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;
 static u32 clear_idx;
        u64 ts_nsec;                    /* time of first print */
        u8 level;                       /* log level of first message */
        u8 facility;                    /* log level of first message */
+       enum log_flags flags;           /* prefix, newline flags */
        bool flushed:1;                 /* buffer sealed and committed */
 } cont;
 
        if (cont.len == 0)
                return;
 
-       log_store(cont.facility, cont.level, LOG_NOCONS | flags,
-                 cont.ts_nsec, NULL, 0, cont.buf, cont.len);
-
-       cont.flushed = true;
+       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, flags | LOG_NOCONS,
+                         cont.ts_nsec, NULL, 0, cont.buf, cont.len);
+               cont.flags = flags;
+               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, flags, 0,
+                         NULL, 0, cont.buf, cont.len);
+               cont.len = 0;
+       }
 }
 
 static bool cont_add(int facility, int level, const char *text, size_t len)
                cont.level = level;
                cont.owner = current;
                cont.ts_nsec = local_clock();
+               cont.flags = 0;
                cont.cons = 0;
                cont.flushed = false;
        }
 
        memcpy(cont.buf + cont.len, text, len);
        cont.len += len;
+
+       if (cont.len > (sizeof(cont.buf) * 80) / 100)
+               cont_flush(LOG_CONT);
+
        return true;
 }
 
        size_t textlen = 0;
        size_t len;
 
-       if (cont.cons == 0) {
+       if (cont.cons == 0 && (console_prev & LOG_NEWLINE)) {
                textlen += print_time(cont.ts_nsec, text);
                size -= textlen;
        }
        }
 
        if (cont.flushed) {
-               text[textlen++] = '\n';
+               if (cont.flags & LOG_NEWLINE)
+                       text[textlen++] = '\n';
                /* got everything, release buffer */
                cont.len = 0;
        }
                 * or another task also prints continuation lines.
                 */
                if (cont.len && (lflags & LOG_PREFIX || cont.owner != current))
-                       cont_flush(0);
+                       cont_flush(LOG_NEWLINE);
 
                /* buffer line if possible, otherwise store it right away */
                if (!cont_add(facility, level, text, text_len))
                if (cont.len && cont.owner == current) {
                        if (!(lflags & LOG_PREFIX))
                                stored = cont_add(facility, level, text, text_len);
-                       cont_flush(0);
+                       cont_flush(LOG_NEWLINE);
                }
 
                if (!stored)
 #define LOG_LINE_MAX 0
 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;
                this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
 }
 
-/* the next printk record to write to the console */
-static u64 console_seq;
-static u32 console_idx;
-static enum log_flags console_prev;
+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;
+
+       /*
+        * 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, text, len);
+       start_critical_timings();
+       local_irq_restore(flags);
+       return;
+out:
+       raw_spin_unlock_irqrestore(&logbuf_lock, flags);
+}
 
 /**
  * console_unlock - unlock the console system
        console_may_schedule = 0;
 
        /* flush buffered message fragment immediately to console */
-       raw_spin_lock_irqsave(&logbuf_lock, flags);
-       if (cont.len && (cont.cons < cont.len || cont.flushed)) {
-               size_t len;
-
-               len = cont_print_text(text, sizeof(text));
-               raw_spin_unlock(&logbuf_lock);
-               stop_critical_timings();
-               call_console_drivers(cont.level, text, len);
-               start_critical_timings();
-               local_irq_restore(flags);
-       } else
-               raw_spin_unlock_irqrestore(&logbuf_lock, flags);
-
+       console_cont_flush(text, sizeof(text));
 again:
        for (;;) {
                struct log *msg;
                         * will properly dump everything later.
                         */
                        msg->flags &= ~LOG_NOCONS;
+                       console_prev = msg->flags;
                        goto skip;
                }