]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
kernel/panic: add verbose logging of kernel taints in backtraces
authorJani Nikula <jani.nikula@intel.com>
Fri, 31 May 2024 09:04:57 +0000 (12:04 +0300)
committerAndrew Morton <akpm@linux-foundation.org>
Tue, 25 Jun 2024 05:25:05 +0000 (22:25 -0700)
With nearly 20 taint flags and respective characters, it's getting a bit
difficult to remember what each taint flag character means.  Add verbose
logging of the set taints in the format:

Tainted: [P]=PROPRIETARY_MODULE, [W]=WARN

in dump_stack_print_info() when there are taints.

Note that the "negative flag" G is not included.

Link: https://lkml.kernel.org/r/7321e306166cb2ca2807ab8639e665baa2462e9c.1717146197.git.jani.nikula@intel.com
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
include/linux/panic.h
kernel/panic.c
lib/dump_stack.c

index 6717b15e798c38904a19ef14bb7dd84fc2a01bb6..3130e0b5116b0367c00ca940cb9aa95e0e95de0d 100644 (file)
@@ -77,9 +77,10 @@ static inline void set_arch_panic_timeout(int timeout, int arch_default_timeout)
 #define TAINT_FLAGS_MAX                        ((1UL << TAINT_FLAGS_COUNT) - 1)
 
 struct taint_flag {
-       char c_true;    /* character printed when tainted */
-       char c_false;   /* character printed when not tainted */
-       bool module;    /* also show as a per-module taint flag */
+       char c_true;            /* character printed when tainted */
+       char c_false;           /* character printed when not tainted */
+       bool module;            /* also show as a per-module taint flag */
+       const char *desc;       /* verbose description of the set taint flag */
 };
 
 extern const struct taint_flag taint_flags[TAINT_FLAGS_COUNT];
@@ -90,6 +91,7 @@ enum lockdep_ok {
 };
 
 extern const char *print_tainted(void);
+extern const char *print_tainted_verbose(void);
 extern void add_taint(unsigned flag, enum lockdep_ok);
 extern int test_taint(unsigned flag);
 extern unsigned long get_taint(void);
index 21975497bfa4c6eaf48f30ae9d6c8bb4888b8e8e..f861bedc1925e748e6589b0196388784ceba302d 100644 (file)
@@ -475,6 +475,7 @@ EXPORT_SYMBOL(panic);
        [ TAINT_##taint ] = {                                           \
                .c_true = _c_true, .c_false = _c_false,                 \
                .module = _module,                                      \
+               .desc = #taint,                                         \
        }
 
 /*
@@ -505,8 +506,9 @@ const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = {
 
 #undef TAINT_FLAG
 
-static void print_tainted_seq(struct seq_buf *s)
+static void print_tainted_seq(struct seq_buf *s, bool verbose)
 {
+       const char *sep = "";
        int i;
 
        if (!tainted_mask) {
@@ -520,10 +522,32 @@ static void print_tainted_seq(struct seq_buf *s)
                bool is_set = test_bit(i, &tainted_mask);
                char c = is_set ? t->c_true : t->c_false;
 
-               seq_buf_putc(s, c);
+               if (verbose) {
+                       if (is_set) {
+                               seq_buf_printf(s, "%s[%c]=%s", sep, c, t->desc);
+                               sep = ", ";
+                       }
+               } else {
+                       seq_buf_putc(s, c);
+               }
        }
 }
 
+static const char *_print_tainted(bool verbose)
+{
+       /* FIXME: what should the size be? */
+       static char buf[sizeof(taint_flags)];
+       struct seq_buf s;
+
+       BUILD_BUG_ON(ARRAY_SIZE(taint_flags) != TAINT_FLAGS_COUNT);
+
+       seq_buf_init(&s, buf, sizeof(buf));
+
+       print_tainted_seq(&s, verbose);
+
+       return seq_buf_str(&s);
+}
+
 /**
  * print_tainted - return a string to represent the kernel taint state.
  *
@@ -534,16 +558,15 @@ static void print_tainted_seq(struct seq_buf *s)
  */
 const char *print_tainted(void)
 {
-       static char buf[TAINT_FLAGS_COUNT + sizeof("Tainted: ")];
-       struct seq_buf s;
-
-       BUILD_BUG_ON(ARRAY_SIZE(taint_flags) != TAINT_FLAGS_COUNT);
-
-       seq_buf_init(&s, buf, sizeof(buf));
-
-       print_tainted_seq(&s);
+       return _print_tainted(false);
+}
 
-       return seq_buf_str(&s);
+/**
+ * print_tainted_verbose - A more verbose version of print_tainted()
+ */
+const char *print_tainted_verbose(void)
+{
+       return _print_tainted(true);
 }
 
 int test_taint(unsigned flag)
index 222c6d6c8281a421b1a58f49b5e11e5048dce784..8b6b70eaf949e67a608a95f9bb679007d5e142ea 100644 (file)
@@ -62,6 +62,9 @@ void dump_stack_print_info(const char *log_lvl)
               (int)strcspn(init_utsname()->version, " "),
               init_utsname()->version, BUILD_ID_VAL);
 
+       if (get_taint())
+               printk("%s%s\n", log_lvl, print_tainted_verbose());
+
        if (dump_stack_arch_desc_str[0] != '\0')
                printk("%sHardware name: %s\n",
                       log_lvl, dump_stack_arch_desc_str);