mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 16:29:59 +00:00
printk: remove console flushing special cases for partial buffered lines
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>
This commit is contained in:
parent
5aa068ea40
commit
5c2992ee7f
1 changed files with 5 additions and 103 deletions
|
@ -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 @@ 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;
|
||||
|
@ -2341,8 +2250,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
|
||||
|
@ -2350,12 +2258,6 @@ 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;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue