Skip to content

Commit c4fcc61

Browse files
jognesspmladek
authored andcommitted
printk: introduce console_prepend_dropped() for dropped messages
Currently "dropped messages" are separately printed immediately before printing the printk message. Since normal consoles are now using an output buffer that is much larger than previously, the "dropped message" could be prepended to the printk message and then output everything in a single write() call. Introduce a helper function console_prepend_dropped() to prepend an existing message with a "dropped message". This simplifies the code by allowing all message formatting to be handled together and then only requires a single write() call to output the full message. And since this helper does not require any locking, it can be used in the future for other console printing contexts as well. Note that console_prepend_dropped() is defined as a NOP for !CONFIG_PRINTK. Although the function will never be called for !CONFIG_PRINTK, compiling the function can lead to warnings of "always true" conditionals due to the size macro values used in !CONFIG_PRINTK. Signed-off-by: John Ogness <[email protected]> Reviewed-by: Petr Mladek <[email protected]> Signed-off-by: Petr Mladek <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 2830eec commit c4fcc61

File tree

2 files changed

+61
-33
lines changed

2 files changed

+61
-33
lines changed

kernel/printk/internal.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write,
2626
/* the maximum size of a formatted extended record */
2727
#define CONSOLE_EXT_LOG_MAX 8192
2828

29-
/* the maximum size for a dropped text message */
30-
#define DROPPED_TEXT_MAX 64
31-
3229
/* the maximum size allowed to be reserved for a record */
3330
#define LOG_LINE_MAX (CONSOLE_LOG_MAX - PREFIX_MAX)
3431

@@ -69,7 +66,6 @@ u16 printk_parse_prefix(const char *text, int *level,
6966
#define PREFIX_MAX 0
7067
#define CONSOLE_LOG_MAX 0
7168
#define CONSOLE_EXT_LOG_MAX 0
72-
#define DROPPED_TEXT_MAX 0
7369
#define LOG_LINE_MAX 0
7470

7571
/*

kernel/printk/printk.c

Lines changed: 61 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1995,27 +1995,6 @@ static int console_trylock_spinning(void)
19951995
return 1;
19961996
}
19971997

1998-
/*
1999-
* Call the specified console driver, asking it to write out the specified
2000-
* text and length. If @dropped_text is non-NULL and any records have been
2001-
* dropped, a dropped message will be written out first.
2002-
*/
2003-
static void call_console_driver(struct console *con, const char *text, size_t len,
2004-
char *dropped_text)
2005-
{
2006-
size_t dropped_len;
2007-
2008-
if (con->dropped && dropped_text) {
2009-
dropped_len = snprintf(dropped_text, DROPPED_TEXT_MAX,
2010-
"** %lu printk messages dropped **\n",
2011-
con->dropped);
2012-
con->dropped = 0;
2013-
con->write(con, dropped_text, dropped_len);
2014-
}
2015-
2016-
con->write(con, text, len);
2017-
}
2018-
20191998
/*
20201999
* Recursion is tracked separately on each CPU. If NMIs are supported, an
20212000
* additional NMI context per CPU is also separately tracked. Until per-CPU
@@ -2395,10 +2374,6 @@ static ssize_t msg_print_ext_body(char *buf, size_t size,
23952374
struct dev_printk_info *dev_info) { return 0; }
23962375
static void console_lock_spinning_enable(void) { }
23972376
static int console_lock_spinning_disable_and_check(int cookie) { return 0; }
2398-
static void call_console_driver(struct console *con, const char *text, size_t len,
2399-
char *dropped_text)
2400-
{
2401-
}
24022377
static bool suppress_message_printing(int level) { return false; }
24032378
static bool pr_flush(int timeout_ms, bool reset_on_progress) { return true; }
24042379
static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress) { return true; }
@@ -2724,6 +2699,56 @@ static void __console_unlock(void)
27242699
up_console_sem();
27252700
}
27262701

2702+
/*
2703+
* Prepend the message in @pmsg->pbufs->outbuf with a "dropped message". This
2704+
* is achieved by shifting the existing message over and inserting the dropped
2705+
* message.
2706+
*
2707+
* @pmsg is the printk message to prepend.
2708+
*
2709+
* @dropped is the dropped count to report in the dropped message.
2710+
*
2711+
* If the message text in @pmsg->pbufs->outbuf does not have enough space for
2712+
* the dropped message, the message text will be sufficiently truncated.
2713+
*
2714+
* If @pmsg->pbufs->outbuf is modified, @pmsg->outbuf_len is updated.
2715+
*/
2716+
#ifdef CONFIG_PRINTK
2717+
static void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped)
2718+
{
2719+
struct printk_buffers *pbufs = pmsg->pbufs;
2720+
const size_t scratchbuf_sz = sizeof(pbufs->scratchbuf);
2721+
const size_t outbuf_sz = sizeof(pbufs->outbuf);
2722+
char *scratchbuf = &pbufs->scratchbuf[0];
2723+
char *outbuf = &pbufs->outbuf[0];
2724+
size_t len;
2725+
2726+
len = snprintf(scratchbuf, scratchbuf_sz,
2727+
"** %lu printk messages dropped **\n", dropped);
2728+
2729+
/*
2730+
* Make sure outbuf is sufficiently large before prepending.
2731+
* Keep at least the prefix when the message must be truncated.
2732+
* It is a rather theoretical problem when someone tries to
2733+
* use a minimalist buffer.
2734+
*/
2735+
if (WARN_ON_ONCE(len + PREFIX_MAX >= outbuf_sz))
2736+
return;
2737+
2738+
if (pmsg->outbuf_len + len >= outbuf_sz) {
2739+
/* Truncate the message, but keep it terminated. */
2740+
pmsg->outbuf_len = outbuf_sz - (len + 1);
2741+
outbuf[pmsg->outbuf_len] = 0;
2742+
}
2743+
2744+
memmove(outbuf + len, outbuf, pmsg->outbuf_len + 1);
2745+
memcpy(outbuf, scratchbuf, len);
2746+
pmsg->outbuf_len += len;
2747+
}
2748+
#else
2749+
#define console_prepend_dropped(pmsg, dropped)
2750+
#endif /* CONFIG_PRINTK */
2751+
27272752
/*
27282753
* Read and format the specified record (or a later record if the specified
27292754
* record is not available).
@@ -2817,7 +2842,6 @@ static bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
28172842
*/
28182843
static bool console_emit_next_record(struct console *con, bool *handover, int cookie)
28192844
{
2820-
static char dropped_text[DROPPED_TEXT_MAX];
28212845
static struct printk_buffers pbufs;
28222846

28232847
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
28402864
goto skip;
28412865
}
28422866

2867+
if (con->dropped && !is_extended) {
2868+
console_prepend_dropped(&pmsg, con->dropped);
2869+
con->dropped = 0;
2870+
}
2871+
28432872
/*
28442873
* While actively printing out messages, if another printk()
28452874
* 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
28532882
printk_safe_enter_irqsave(flags);
28542883
console_lock_spinning_enable();
28552884

2856-
stop_critical_timings(); /* don't trace print latency */
2857-
call_console_driver(con, outbuf, pmsg.outbuf_len,
2858-
is_extended ? NULL : dropped_text);
2885+
/* Do not trace print latency. */
2886+
stop_critical_timings();
2887+
2888+
/* Write everything out to the hardware. */
2889+
con->write(con, outbuf, pmsg.outbuf_len);
2890+
28592891
start_critical_timings();
28602892

28612893
con->seq = pmsg.seq + 1;

0 commit comments

Comments
 (0)