diff options
-rw-r--r-- | kernel/printk/internal.h | 4 | ||||
-rw-r--r-- | kernel/printk/printk.c | 90 |
2 files changed, 61 insertions, 33 deletions
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h index c9bb0cd86372..72df730597f1 100644 --- a/kernel/printk/internal.h +++ b/kernel/printk/internal.h @@ -26,9 +26,6 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write, /* the maximum size of a formatted extended record */ #define CONSOLE_EXT_LOG_MAX 8192 -/* the maximum size for a dropped text message */ -#define DROPPED_TEXT_MAX 64 - /* the maximum size allowed to be reserved for a record */ #define LOG_LINE_MAX (CONSOLE_LOG_MAX - PREFIX_MAX) @@ -69,7 +66,6 @@ u16 printk_parse_prefix(const char *text, int *level, #define PREFIX_MAX 0 #define CONSOLE_LOG_MAX 0 #define CONSOLE_EXT_LOG_MAX 0 -#define DROPPED_TEXT_MAX 0 #define LOG_LINE_MAX 0 /* diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 6e2a6d5548e9..80a49ec6f42b 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1996,27 +1996,6 @@ static int console_trylock_spinning(void) } /* - * Call the specified console driver, asking it to write out the specified - * text and length. If @dropped_text is non-NULL and any records have been - * dropped, a dropped message will be written out first. - */ -static void call_console_driver(struct console *con, const char *text, size_t len, - char *dropped_text) -{ - size_t dropped_len; - - if (con->dropped && dropped_text) { - dropped_len = snprintf(dropped_text, DROPPED_TEXT_MAX, - "** %lu printk messages dropped **\n", - con->dropped); - con->dropped = 0; - con->write(con, dropped_text, dropped_len); - } - - con->write(con, text, len); -} - -/* * Recursion is tracked separately on each CPU. If NMIs are supported, an * additional NMI context per CPU is also separately tracked. Until per-CPU * is available, a separate "early tracking" is performed. @@ -2395,10 +2374,6 @@ static ssize_t msg_print_ext_body(char *buf, size_t size, struct dev_printk_info *dev_info) { return 0; } static void console_lock_spinning_enable(void) { } static int console_lock_spinning_disable_and_check(int cookie) { return 0; } -static void call_console_driver(struct console *con, const char *text, size_t len, - char *dropped_text) -{ -} static bool suppress_message_printing(int level) { return false; } static bool pr_flush(int timeout_ms, bool reset_on_progress) { return true; } static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress) { return true; } @@ -2725,6 +2700,56 @@ static void __console_unlock(void) } /* + * Prepend the message in @pmsg->pbufs->outbuf with a "dropped message". This + * is achieved by shifting the existing message over and inserting the dropped + * message. + * + * @pmsg is the printk message to prepend. + * + * @dropped is the dropped count to report in the dropped message. + * + * If the message text in @pmsg->pbufs->outbuf does not have enough space for + * the dropped message, the message text will be sufficiently truncated. + * + * If @pmsg->pbufs->outbuf is modified, @pmsg->outbuf_len is updated. + */ +#ifdef CONFIG_PRINTK +static void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped) +{ + struct printk_buffers *pbufs = pmsg->pbufs; + const size_t scratchbuf_sz = sizeof(pbufs->scratchbuf); + const size_t outbuf_sz = sizeof(pbufs->outbuf); + char *scratchbuf = &pbufs->scratchbuf[0]; + char *outbuf = &pbufs->outbuf[0]; + size_t len; + + len = snprintf(scratchbuf, scratchbuf_sz, + "** %lu printk messages dropped **\n", dropped); + + /* + * Make sure outbuf is sufficiently large before prepending. + * Keep at least the prefix when the message must be truncated. + * It is a rather theoretical problem when someone tries to + * use a minimalist buffer. + */ + if (WARN_ON_ONCE(len + PREFIX_MAX >= outbuf_sz)) + return; + + if (pmsg->outbuf_len + len >= outbuf_sz) { + /* Truncate the message, but keep it terminated. */ + pmsg->outbuf_len = outbuf_sz - (len + 1); + outbuf[pmsg->outbuf_len] = 0; + } + + memmove(outbuf + len, outbuf, pmsg->outbuf_len + 1); + memcpy(outbuf, scratchbuf, len); + pmsg->outbuf_len += len; +} +#else +#define console_prepend_dropped(pmsg, dropped) +#endif /* CONFIG_PRINTK */ + +/* * Read and format the specified record (or a later record if the specified * record is not available). * @@ -2817,7 +2842,6 @@ out: */ static bool console_emit_next_record(struct console *con, bool *handover, int cookie) { - static char dropped_text[DROPPED_TEXT_MAX]; static struct printk_buffers pbufs; bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED; @@ -2840,6 +2864,11 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co goto skip; } + if (con->dropped && !is_extended) { + console_prepend_dropped(&pmsg, con->dropped); + con->dropped = 0; + } + /* * While actively printing out messages, if another printk() * were to occur on another CPU, it may wait for this one to @@ -2853,9 +2882,12 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co printk_safe_enter_irqsave(flags); console_lock_spinning_enable(); - stop_critical_timings(); /* don't trace print latency */ - call_console_driver(con, outbuf, pmsg.outbuf_len, - is_extended ? NULL : dropped_text); + /* Do not trace print latency. */ + stop_critical_timings(); + + /* Write everything out to the hardware. */ + con->write(con, outbuf, pmsg.outbuf_len); + start_critical_timings(); con->seq = pmsg.seq + 1; |