Introduce LOUD_CON flag to printk. The new flag will make it possible to create a context where printk messages will never be suppressed. This new context information will be stored in the already existing printk_context per-CPU variable. This variable was changed from 'int' to 'unsigned int' to avoid issues with automatic casting. This mechanism will be used in the next patch to create a loud_console context on sysrq handling, removing an existing workaround on the loglevel global variable. The workaround existed to make sure that sysrq header messages were sent to all consoles. Signed-off-by: Marcos Paulo de Souza <mpdesouza@xxxxxxxx> --- include/linux/printk.h | 3 +++ kernel/printk/internal.h | 3 +++ kernel/printk/printk.c | 8 +++++++- kernel/printk/printk_safe.c | 27 +++++++++++++++++++++++++-- 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/include/linux/printk.h b/include/linux/printk.h index eca9bb2ee637..0ac9879d94ac 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -166,6 +166,9 @@ __printf(1, 2) __cold int _printk_deferred(const char *fmt, ...); extern void __printk_deferred_enter(void); extern void __printk_deferred_exit(void); +extern void printk_loud_console_enter(void); +extern void printk_loud_console_exit(void); + /* * The printk_deferred_enter/exit macros are available only as a hack for * some code paths that need to defer all printk console printing. Interrupts diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h index 3fcb48502adb..2649e8a66cef 100644 --- a/kernel/printk/internal.h +++ b/kernel/printk/internal.h @@ -53,6 +53,8 @@ int devkmsg_sysctl_set_loglvl(const struct ctl_table *table, int write, /* Flags for a single printk record. */ enum printk_info_flags { + /* always show on console, ignore console_loglevel */ + LOG_LOUD_CON = 1, LOG_NEWLINE = 2, /* text ended with a newline */ LOG_CONT = 8, /* text is a fragment of a continuation line */ }; @@ -90,6 +92,7 @@ bool printk_percpu_data_ready(void); void defer_console_output(void); bool is_printk_legacy_deferred(void); +bool is_printk_console_loud(void); u16 printk_parse_prefix(const char *text, int *level, enum printk_info_flags *flags); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index beb808f4c367..b893825fe21d 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1321,6 +1321,7 @@ static void boot_delay_msec(int level) unsigned long timeout; if ((boot_delay == 0 || system_state >= SYSTEM_RUNNING) + || is_printk_console_loud() || suppress_message_printing(level)) { return; } @@ -2273,6 +2274,9 @@ int vprintk_store(int facility, int level, if (dev_info) flags |= LOG_NEWLINE; + if (is_printk_console_loud()) + flags |= LOG_LOUD_CON; + if (flags & LOG_CONT) { prb_rec_init_wr(&r, reserve_size); if (prb_reserve_in_last(&e, prb, &r, caller_id, PRINTKRB_RECORD_MAX)) { @@ -2947,6 +2951,7 @@ bool printk_get_next_message(struct printk_message *pmsg, u64 seq, struct printk_info info; struct printk_record r; size_t len = 0; + bool loud_con; /* * Formatting extended messages requires a separate buffer, so use the @@ -2965,9 +2970,10 @@ bool printk_get_next_message(struct printk_message *pmsg, u64 seq, pmsg->seq = r.info->seq; pmsg->dropped = r.info->seq - seq; + loud_con = r.info->flags & LOG_LOUD_CON; /* Skip record that has level above the console loglevel. */ - if (may_suppress && suppress_message_printing(r.info->level)) + if (!loud_con && may_suppress && suppress_message_printing(r.info->level)) goto out; if (is_extended) { diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c index 2b35a9d3919d..4618988baeea 100644 --- a/kernel/printk/printk_safe.c +++ b/kernel/printk/printk_safe.c @@ -12,7 +12,30 @@ #include "internal.h" -static DEFINE_PER_CPU(int, printk_context); +static DEFINE_PER_CPU(unsigned int, printk_context); + +#define PRINTK_SAFE_CONTEXT_MASK 0x0000ffffU +#define PRINTK_LOUD_CONSOLE_CONTEXT_MASK 0xffff0000U +#define PRINTK_LOUD_CONSOLE_CONTEXT_OFFSET 0x00010000U + +void noinstr printk_loud_console_enter(void) +{ + cant_migrate(); + this_cpu_add(printk_context, PRINTK_LOUD_CONSOLE_CONTEXT_OFFSET); +} + +void noinstr printk_loud_console_exit(void) +{ + cant_migrate(); + this_cpu_sub(printk_context, PRINTK_LOUD_CONSOLE_CONTEXT_OFFSET); +} + +/* Safe in any context. CPU migration is always disabled when set. */ +bool is_printk_console_loud(void) +{ + return !!(this_cpu_read(printk_context) & + PRINTK_LOUD_CONSOLE_CONTEXT_MASK); +} /* Can be preempted by NMI. */ void __printk_safe_enter(void) @@ -45,7 +68,7 @@ bool is_printk_legacy_deferred(void) * context. CPU migration is always disabled when set. */ return (force_legacy_kthread() || - this_cpu_read(printk_context) || + !!(this_cpu_read(printk_context) & PRINTK_SAFE_CONTEXT_MASK) || in_nmi()); } -- 2.46.1