| From: Jani Nikula <jani.nikula@intel.com> |
| Subject: kernel/panic: add verbose logging of kernel taints in backtraces |
| Date: Fri, 31 May 2024 12:04:57 +0300 |
| |
| 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 | 8 ++++--- |
| kernel/panic.c | 45 ++++++++++++++++++++++++++++++---------- |
| lib/dump_stack.c | 3 ++ |
| 3 files changed, 42 insertions(+), 14 deletions(-) |
| |
| --- a/include/linux/panic.h~kernel-panic-add-verbose-logging-of-kernel-taints-in-backtraces |
| +++ a/include/linux/panic.h |
| @@ -77,9 +77,10 @@ static inline void set_arch_panic_timeou |
| #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); |
| --- a/kernel/panic.c~kernel-panic-add-verbose-logging-of-kernel-taints-in-backtraces |
| +++ a/kernel/panic.c |
| @@ -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[TAIN |
| |
| #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 |
| 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 |
| */ |
| 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) |
| --- a/lib/dump_stack.c~kernel-panic-add-verbose-logging-of-kernel-taints-in-backtraces |
| +++ a/lib/dump_stack.c |
| @@ -62,6 +62,9 @@ void dump_stack_print_info(const char *l |
| (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); |
| _ |