[PATCH] printk: Add loglevel for "do not print to consoles".

From: Tetsuo Handa
Date: Thu Apr 23 2020 - 22:43:02 EST


Since dump_tasks() is capable of generating thousands of printk() lines,
it can significantly delay solving OOM situation by killing a process
via the OOM killer. There is /proc/sys/vm/oom_dump_tasks which allows
suppressing dump_tasks(), but those who diagnose the reason of OOM need
dump_tasks() in order to understand memory usage as of invocation of the
OOM killer. Therefore, setting /proc/sys/vm/oom_dump_tasks to 0 cannot be
an option. Also, since userspace syslog daemon is likely configured not
to save low (e.g. KERN_DEBUG) loglevels, reducing loglevel used by
dump_tasks() cannot be an option. We want to maintain current loglevels
in order to allow saving kernel messages to log files while we also want
to avoid delays caused by printing to consoles due to maintaining current
loglevels.

While an attempt to make printk() asynchronous (i.e. defer printing to
consoles) and an attempt to make printk() to print to only selected
consoles (i.e. don't print unimportant messages to slow consoles) are
in progress, there are printk() callers where saving to log files is
useful for later analysis but printing to consoles for immediate
notification makes little sense. Two examples of such printk() callers
will be the OOM killer and memory allocation failure messages. Therefore,
this patch introduces a loglevel KERN_NO_CONSOLES which prevents all
consoles from printing such messages.

Since both KERN_NO_CONSOLES messages and !KERN_NO_CONSOLES messages are
stored into common printk buffer, KERN_NO_CONSOLES messages will be
retrievable from the vmcore file even if something bad (e.g. NULL pointer
dereference) followed. Therefore, as long as a system is configured for
later analysis, ability to suppress printing to consoles will be useful.
Since Dmitry Safonov is working on adding loglevel argument to
show_stack(), we will in near future be able to control whether
dump_stack() output is important enough to immediately print to consoles,
by adding loglevel argument to dump_stack().

Signed-off-by: Tetsuo Handa <penguin-kernel@xxxxxxxxxxxxxxxxxxx>
Cc: Dmitry Safonov <dima@xxxxxxxxxx>
Cc: Michal Hocko <mhocko@xxxxxxxx>
Cc: Yafang Shao <laoar.shao@xxxxxxxxx>
---
include/linux/kern_levels.h | 3 +++
include/linux/printk.h | 1 +
kernel/printk/printk.c | 7 ++++++-
3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/include/linux/kern_levels.h b/include/linux/kern_levels.h
index bf2389c26ae3..cd69a9cb3c2a 100644
--- a/include/linux/kern_levels.h
+++ b/include/linux/kern_levels.h
@@ -23,6 +23,9 @@
*/
#define KERN_CONT KERN_SOH "c"

+/* Annotation for "don't print to consoles". */
+#define KERN_NO_CONSOLES KERN_SOH "S"
+
/* integer equivalents of KERN_<LEVEL> */
#define LOGLEVEL_SCHED -2 /* Deferred messages from sched code
* are set to this special level */
diff --git a/include/linux/printk.h b/include/linux/printk.h
index e061635e0409..da338b81c2e1 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -19,6 +19,7 @@ static inline int printk_get_level(const char *buffer)
switch (buffer[1]) {
case '0' ... '7':
case 'c': /* KERN_CONT */
+ case 'S': /* KERN_NO_CONSOLES */
return buffer[1];
}
}
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 9a9b6156270b..ed51641af087 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -361,6 +361,7 @@ static int console_msg_format = MSG_FORMAT_DEFAULT;
*/

enum log_flags {
+ LOG_NO_CONSOLES = 1, /* don't print to consoles */
LOG_NEWLINE = 2, /* text ended with a newline */
LOG_CONT = 8, /* text is a fragment of a continuation line */
};
@@ -1959,6 +1960,9 @@ int vprintk_store(int facility, int level,
break;
case 'c': /* KERN_CONT */
lflags |= LOG_CONT;
+ break;
+ case 'S': /* KERN_NO_CONSOLES */
+ lflags |= LOG_NO_CONSOLES;
}

text_len -= 2;
@@ -2453,7 +2457,8 @@ void console_unlock(void)
break;

msg = log_from_idx(console_idx);
- if (suppress_message_printing(msg->level)) {
+ if ((msg->flags & LOG_NO_CONSOLES) ||
+ suppress_message_printing(msg->level)) {
/*
* Skip record we have buffered and already printed
* directly to the console when we received it, and
--
2.18.2