[RFC PATCH] printk: Possible solution for loglevel manipulation by earlyparams

From: Petr Mladek
Date: Wed Sep 05 2018 - 06:57:18 EST


Early params that manipulate console_loglevel should invalidate
LOG_NOCONS flag for all the existing messages.
---
include/linux/console.h | 2 ++
init/main.c | 6 +++---
kernel/printk/printk.c | 27 +++++++++++++++++++++++----
3 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/include/linux/console.h b/include/linux/console.h
index ec9bdb3d7bab..3d3f7ab8f82e 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -195,6 +195,8 @@ extern bool console_suspend_enabled;
extern void suspend_console(void);
extern void resume_console(void);

+extern void console_set_default_loglevel(int loglevel);
+
int mda_console_init(void);
void prom_con_init(void);

diff --git a/init/main.c b/init/main.c
index 18f8f0140fa0..936466209494 100644
--- a/init/main.c
+++ b/init/main.c
@@ -213,13 +213,13 @@ EXPORT_SYMBOL(loops_per_jiffy);

static int __init debug_kernel(char *str)
{
- console_loglevel = CONSOLE_LOGLEVEL_DEBUG;
+ console_set_default_loglevel(CONSOLE_LOGLEVEL_DEBUG);
return 0;
}

static int __init quiet_kernel(char *str)
{
- console_loglevel = CONSOLE_LOGLEVEL_QUIET;
+ console_set_default_loglevel(CONSOLE_LOGLEVEL_QUIET);
return 0;
}

@@ -236,7 +236,7 @@ static int __init loglevel(char *str)
* are quite hard to debug
*/
if (get_option(&str, &newlevel)) {
- console_loglevel = newlevel;
+ console_set_default_loglevel(newlevel);
return 0;
}

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 924e37fb1620..b5a0074302e9 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -430,6 +430,9 @@ static u32 console_idx;
static u64 clear_seq;
static u32 clear_idx;

+/* Invalidate nocons flag setting before early param are proceed */
+static u64 console_valid_nocons_seq;
+
#define PREFIX_MAX 32
#define LOG_LINE_MAX (1024 - PREFIX_MAX)

@@ -1148,11 +1151,19 @@ module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ignore_loglevel,
"ignore loglevel setting (prints all kernel messages to the console)");

-static bool suppress_message_printing(int level)
+static bool nocons_loglevel(int level)
{
return (level >= console_loglevel && !ignore_loglevel);
}

+static bool nocons_msg(struct printk_log *msg)
+{
+ if (console_seq >= console_valid_nocons_seq)
+ return msg->flags & LOG_NOCONS;
+
+ return nocons_loglevel(msg->level);
+}
+
#ifdef CONFIG_BOOT_PRINTK_DELAY

static int boot_delay; /* msecs delay after each printk during bootup */
@@ -1182,7 +1193,7 @@ static void boot_delay_msec(int level)
unsigned long timeout;

if ((boot_delay == 0 || system_state >= SYSTEM_RUNNING)
- || suppress_message_printing(level)) {
+ || nocons_loglevel(level)) {
return;
}

@@ -1882,7 +1893,7 @@ int vprintk_store(int facility, int level,
if (dict)
lflags |= LOG_PREFIX|LOG_NEWLINE;

- if (suppress_message_printing(level))
+ if (nocons_loglevel(level))
lflags |= LOG_NOCONS;

return log_output(facility, level, lflags,
@@ -2031,6 +2042,7 @@ static void console_lock_spinning_enable(void) { }
static int console_lock_spinning_disable_and_check(void) { return 0; }
static void call_console_drivers(const char *ext_text, size_t ext_len,
const char *text, size_t len) {}
+static bool nocons_msg(struct printk_log *msg) { return false; }
static size_t msg_print_text(const struct printk_log *msg,
bool syslog, char *buf, size_t size) { return 0; }

@@ -2197,6 +2209,13 @@ void resume_console(void)
console_unlock();
}

+void console_set_default_loglevel(int loglevel)
+{
+ console_loglevel = loglevel;
+ /* Invalidate nocons flag for earlier messages. */
+ console_valid_nocons_seq = log_next_seq;
+}
+
/**
* console_cpu_notify - print deferred console messages after CPU hotplug
* @cpu: unused
@@ -2369,7 +2388,7 @@ void console_unlock(void)
break;

msg = log_from_idx(console_idx);
- if (msg->flags & LOG_NOCONS) {
+ if (nocons_msg(msg)) {
/*
* Skip record if !ignore_loglevel, and
* record has level above the console loglevel.
--
2.13.7