While handling sysrq the console_loglevel is bumped to default to print
sysrq headers. It's done to print sysrq messages with WARNING level for
consumers of /proc/kmsg, though it sucks by the following reasons:
- changing console_loglevel may produce tons of messages (especially on
  bloated with debug/info prints systems)
- it doesn't guarantee that the message will be printed as printk may
  deffer the actual console output from buffer (see the comment near
  printk() in kernel/printk/printk.c)

Provide KERN_UNSUPPRESSED printk() annotation for such legacy places.
Make sysrq print the headers unsuppressed instead of changing
console_loglevel.

Cc: Greg Kroah-Hartman <gre...@linuxfoundation.org>
Cc: Jiri Slaby <jsl...@suse.com>
Cc: Petr Mladek <pmla...@suse.com>
Cc: Sergey Senozhatsky <sergey.senozhat...@gmail.com>
Cc: Steven Rostedt <rost...@goodmis.org>
Cc: Tetsuo Handa <penguin-ker...@i-love.sakura.ne.jp>
Signed-off-by: Dmitry Safonov <d...@arista.com>
---
(I'm not fond at all of this patch - sending as RFC just to touch
 how you all feel about this..)

 drivers/tty/sysrq.c         | 34 ++++++++++++++++++----------------
 include/linux/kern_levels.h |  6 ++++++
 include/linux/printk.h      |  1 +
 kernel/printk/printk.c      | 17 ++++++++++++-----
 4 files changed, 37 insertions(+), 21 deletions(-)

diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 59e82e6d776d..ea37e3aa84b3 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -523,23 +523,28 @@ static void __sysrq_put_key_op(int key, struct 
sysrq_key_op *op_p)
                 sysrq_key_table[i] = op_p;
 }
 
+#if (CONSOLE_LOGLEVEL_DEFAULT > LOGLEVEL_INFO)
+#define KERN_SYSRQ             KERN_UNSUPPRESSED
+#else
+#define KERN_SYSRQ
+#endif
+#define sysrq_info(fmt, ...)   \
+       printk(KERN_SYSRQ KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
+#define sysrq_cont(fmt, ...)   \
+       printk(KERN_SYSRQ KERN_CONT pr_fmt(fmt), ##__VA_ARGS__)
+
 void __handle_sysrq(int key, bool check_mask)
 {
        struct sysrq_key_op *op_p;
-       int orig_log_level;
        int i;
 
        rcu_sysrq_start();
        rcu_read_lock();
+
        /*
-        * Raise the apparent loglevel to maximum so that the sysrq header
-        * is shown to provide the user with positive feedback.  We do not
-        * simply emit this at KERN_EMERG as that would change message
-        * routing in the consumers of /proc/kmsg.
+        * We do not simply emit this at KERN_EMERG as that would change
+        * message routing in the consumers of /proc/kmsg.
         */
-       orig_log_level = console_loglevel;
-       console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
-
         op_p = __sysrq_get_key_op(key);
         if (op_p) {
                /*
@@ -547,15 +552,13 @@ void __handle_sysrq(int key, bool check_mask)
                 * should not) and is the invoked operation enabled?
                 */
                if (!check_mask || sysrq_on_mask(op_p->enable_mask)) {
-                       pr_info("%s\n", op_p->action_msg);
-                       console_loglevel = orig_log_level;
+                       sysrq_info("%s\n", op_p->action_msg);
                        op_p->handler(key);
                } else {
-                       pr_info("This sysrq operation is disabled.\n");
-                       console_loglevel = orig_log_level;
+                       sysrq_info("This sysrq operation is disabled.\n");
                }
        } else {
-               pr_info("HELP : ");
+               sysrq_info("HELP : ");
                /* Only print the help msg once per handler */
                for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) {
                        if (sysrq_key_table[i]) {
@@ -566,11 +569,10 @@ void __handle_sysrq(int key, bool check_mask)
                                        ;
                                if (j != i)
                                        continue;
-                               pr_cont("%s ", sysrq_key_table[i]->help_msg);
+                               sysrq_cont("%s ", sysrq_key_table[i]->help_msg);
                        }
                }
-               pr_cont("\n");
-               console_loglevel = orig_log_level;
+               sysrq_cont("\n");
        }
        rcu_read_unlock();
        rcu_sysrq_end();
diff --git a/include/linux/kern_levels.h b/include/linux/kern_levels.h
index bf2389c26ae3..2f40d6ace60d 100644
--- a/include/linux/kern_levels.h
+++ b/include/linux/kern_levels.h
@@ -23,6 +23,12 @@
  */
 #define KERN_CONT      KERN_SOH "c"
 
+/*
+ * Annotation for a message that will be printed regardless current
+ * console_loglevel. _DO_NOT_USE_IT! Exists for legacy code.
+ */
+#define KERN_UNSUPPRESSED      KERN_SOH "u"
+
 /* 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 84ea4d094af3..60a5cfde1488 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 'u':       /* KERN_UNSUPPRESSED */
                        return buffer[1];
                }
        }
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 02ca827b8fac..c6dd82c37382 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -345,6 +345,7 @@ static int console_msg_format = MSG_FORMAT_DEFAULT;
 
 enum log_flags {
        LOG_NEWLINE     = 2,    /* text ended with a newline */
+       LOG_DONT_SUPPRESS = 4,  /* ignore current console_loglevel */
        LOG_CONT        = 8,    /* text is a fragment of a continuation line */
 };
 
@@ -1179,9 +1180,12 @@ 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 suppress_message_printing(int level, u8 lflags)
 {
-       return (level >= console_loglevel && !ignore_loglevel);
+       if (ignore_loglevel || (lflags & LOG_DONT_SUPPRESS))
+               return false;
+
+       return level >= console_loglevel;
 }
 
 #ifdef CONFIG_BOOT_PRINTK_DELAY
@@ -1213,7 +1217,7 @@ static void boot_delay_msec(int level)
        unsigned long timeout;
 
        if ((boot_delay == 0 || system_state >= SYSTEM_RUNNING)
-               || suppress_message_printing(level)) {
+               || suppress_message_printing(level, 0)) {
                return;
        }
 
@@ -1917,6 +1921,9 @@ int vprintk_store(int facility, int level,
                                break;
                        case 'c':       /* KERN_CONT */
                                lflags |= LOG_CONT;
+                               break;
+                       case 'u':       /* KERN_UNSUPPRESSED */
+                               lflags |= LOG_DONT_SUPPRESS;
                        }
 
                        text_len -= 2;
@@ -2069,7 +2076,7 @@ static void call_console_drivers(const char *ext_text, 
size_t ext_len,
                                 const char *text, size_t len) {}
 static size_t msg_print_text(const struct printk_log *msg, bool syslog,
                             bool time, char *buf, size_t size) { return 0; }
-static bool suppress_message_printing(int level) { return false; }
+static bool suppress_message_printing(int level, u8 lflags) { return false; }
 
 #endif /* CONFIG_PRINTK */
 
@@ -2407,7 +2414,7 @@ void console_unlock(void)
                        break;
 
                msg = log_from_idx(console_idx);
-               if (suppress_message_printing(msg->level)) {
+               if (suppress_message_printing(msg->level, msg->flags)) {
                        /*
                         * Skip record we have buffered and already printed
                         * directly to the console when we received it, and
-- 
2.21.0

Reply via email to