Currently the parameter "panic_print" relies in a function called directly on panic path; one of the flags the users can set for panic_print triggers a console replay mechanism, to show the entire kernel log buffer (from the beginning) in a panic event. Two problems with that: the dual nature of the panic_print isn't really appropriate, the function was originally meant to allow users dumping system information on panic events, and was "overridden" to also force a console flush of the full kernel log buffer. It also turns the code a bit more complex and duplicate than it needs to be. This patch proposes 2 changes: first, we decouple panic_print from the console flushing mechanism, in the form of a new kernel core parameter (panic_console_replay); we kept the functionality on panic_print to avoid userspace breakage, although we comment in both code and documentation that this panic_print usage is deprecated. We converted panic_print function to a panic notifier too, adding it on the panic informational notifier list, executed as the final callback. This allows a more clear code and makes sense, as panic_print_sys_info() is really a panic-time only function. We also moved its code to kernel/printk.c, it seems to make more sense given it's related to printing stuff. Suggested-by: Petr Mladek <pmladek@xxxxxxxx> Signed-off-by: Guilherme G. Piccoli <gpiccoli@xxxxxxxxxx> --- .../admin-guide/kernel-parameters.txt | 12 +++- Documentation/admin-guide/sysctl/kernel.rst | 5 +- include/linux/console.h | 2 + include/linux/panic.h | 1 - include/linux/printk.h | 1 + kernel/panic.c | 51 +++------------ kernel/printk/printk.c | 62 +++++++++++++++++++ 7 files changed, 87 insertions(+), 47 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 8d3524060ce3..c99da8b2b216 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3791,6 +3791,14 @@ timeout < 0: reboot immediately Format: <timeout> + panic_console_replay + [KNL] Force a kernel log replay in the console on + panic event. Notice that there is already a flush + mechanism for pending messages; this option is meant + for users that wish to replay the *full* buffer. + It deprecates the bit 5 setting on "panic_print", + both having the same functionality. + panic_notifiers_level= [KNL] Set the panic notifiers execution order. Format: <unsigned int> @@ -3825,12 +3833,14 @@ bit 2: print timer info bit 3: print locks info if CONFIG_LOCKDEP is on bit 4: print ftrace buffer - bit 5: print all printk messages in buffer + bit 5: print all printk messages in buffer (DEPRECATED) bit 6: print all CPUs backtrace (if available in the arch) *Be aware* that this option may print a _lot_ of lines, so there are risks of losing older messages in the log. Use this option carefully, maybe worth to setup a bigger log buffer with "log_buf_len" along with this. + Also, notice that bit 5 was deprecated in favor of the + parameter "panic_console_replay". panic_on_taint= Bitmask for conditionally calling panic() in add_taint() Format: <hex>[,nousertaint] diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst index 1144ea3229a3..17b293a0e566 100644 --- a/Documentation/admin-guide/sysctl/kernel.rst +++ b/Documentation/admin-guide/sysctl/kernel.rst @@ -763,10 +763,13 @@ bit 1 print system memory info bit 2 print timer info bit 3 print locks info if ``CONFIG_LOCKDEP`` is on bit 4 print ftrace buffer -bit 5 print all printk messages in buffer +bit 5 print all printk messages in buffer (DEPRECATED) bit 6 print all CPUs backtrace (if available in the arch) ===== ============================================ +Notice that bit 5 was deprecated in favor of kernel core parameter +"panic_console_replay" (see kernel-parameters.txt documentation). + So for example to print tasks and memory info on panic, user can:: echo 3 > /proc/sys/kernel/panic_print diff --git a/include/linux/console.h b/include/linux/console.h index 7cd758a4f44e..351c14f623ad 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -169,6 +169,8 @@ enum con_flush_mode { CONSOLE_REPLAY_ALL, }; +extern bool panic_console_replay; + extern int add_preferred_console(char *name, int idx, char *options); extern void register_console(struct console *); extern int unregister_console(struct console *); diff --git a/include/linux/panic.h b/include/linux/panic.h index f5844908a089..34175d0188d0 100644 --- a/include/linux/panic.h +++ b/include/linux/panic.h @@ -22,7 +22,6 @@ extern unsigned int sysctl_oops_all_cpu_backtrace; #endif /* CONFIG_SMP */ extern int panic_timeout; -extern unsigned long panic_print; extern int panic_on_oops; extern int panic_on_unrecovered_nmi; extern int panic_on_io_nmi; diff --git a/include/linux/printk.h b/include/linux/printk.h index 1522df223c0f..aee2e8ebd541 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -13,6 +13,7 @@ extern const char linux_banner[]; extern const char linux_proc_banner[]; +extern unsigned long panic_print; extern int oops_in_progress; /* If set, an oops, panic(), BUG() or die() is in progress */ #define PRINTK_MAX_SINGLE_HEADER_LEN 2 diff --git a/kernel/panic.c b/kernel/panic.c index b7c055d4f87f..ff257bd8f81b 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -68,15 +68,6 @@ unsigned int panic_notifiers_level = 2; /* DEPRECATED in favor of panic_notifiers_level */ bool crash_kexec_post_notifiers; -#define PANIC_PRINT_TASK_INFO 0x00000001 -#define PANIC_PRINT_MEM_INFO 0x00000002 -#define PANIC_PRINT_TIMER_INFO 0x00000004 -#define PANIC_PRINT_LOCK_INFO 0x00000008 -#define PANIC_PRINT_FTRACE_INFO 0x00000010 -#define PANIC_PRINT_ALL_PRINTK_MSG 0x00000020 -#define PANIC_PRINT_ALL_CPU_BT 0x00000040 -unsigned long panic_print; - ATOMIC_NOTIFIER_HEAD(panic_hypervisor_list); EXPORT_SYMBOL(panic_hypervisor_list); @@ -168,33 +159,6 @@ void nmi_panic(struct pt_regs *regs, const char *msg) } EXPORT_SYMBOL(nmi_panic); -static void panic_print_sys_info(bool console_flush) -{ - if (console_flush) { - if (panic_print & PANIC_PRINT_ALL_PRINTK_MSG) - console_flush_on_panic(CONSOLE_REPLAY_ALL); - return; - } - - if (panic_print & PANIC_PRINT_ALL_CPU_BT) - trigger_all_cpu_backtrace(); - - if (panic_print & PANIC_PRINT_TASK_INFO) - show_state(); - - if (panic_print & PANIC_PRINT_MEM_INFO) - show_mem(0, NULL); - - if (panic_print & PANIC_PRINT_TIMER_INFO) - sysrq_timer_list_show(); - - if (panic_print & PANIC_PRINT_LOCK_INFO) - debug_show_all_locks(); - - if (panic_print & PANIC_PRINT_FTRACE_INFO) - ftrace_dump(DUMP_ALL); -} - /* * Helper that accumulates all console flushing routines executed on panic. */ @@ -218,7 +182,11 @@ static void console_flushing(void) debug_locks_off(); console_flush_on_panic(CONSOLE_FLUSH_PENDING); - panic_print_sys_info(true); + /* In case users wish to replay the full log buffer... */ + if (panic_console_replay) { + pr_warn("Replaying the log buffer from the beginning\n"); + console_flush_on_panic(CONSOLE_REPLAY_ALL); + } } #define PN_HYPERVISOR_BIT 0 @@ -431,10 +399,8 @@ void panic(const char *fmt, ...) crash_smp_send_stop(); panic_notifier_hypervisor_once(buf); - if (panic_notifier_info_once(buf)) { - panic_print_sys_info(false); + if (panic_notifier_info_once(buf)) kmsg_dump(KMSG_DUMP_PANIC); - } panic_notifier_pre_reboot_once(buf); @@ -442,10 +408,8 @@ void panic(const char *fmt, ...) panic_notifier_hypervisor_once(buf); - if (panic_notifier_info_once(buf)) { - panic_print_sys_info(false); + if (panic_notifier_info_once(buf)) kmsg_dump(KMSG_DUMP_PANIC); - } panic_notifier_pre_reboot_once(buf); @@ -814,7 +778,6 @@ EXPORT_SYMBOL(__stack_chk_fail); #endif core_param(panic, panic_timeout, int, 0644); -core_param(panic_print, panic_print, ulong, 0644); core_param(pause_on_oops, pause_on_oops, int, 0644); core_param(panic_on_warn, panic_on_warn, int, 0644); core_param(panic_notifiers_level, panic_notifiers_level, uint, 0644); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index e3a1c429fbbc..ad91d4c04246 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -35,6 +35,7 @@ #include <linux/memblock.h> #include <linux/syscalls.h> #include <linux/crash_core.h> +#include <linux/panic_notifier.h> #include <linux/ratelimit.h> #include <linux/kmsg_dump.h> #include <linux/syslog.h> @@ -3234,6 +3235,61 @@ void __init console_init(void) } } +#define PANIC_PRINT_TASK_INFO 0x00000001 +#define PANIC_PRINT_MEM_INFO 0x00000002 +#define PANIC_PRINT_TIMER_INFO 0x00000004 +#define PANIC_PRINT_LOCK_INFO 0x00000008 +#define PANIC_PRINT_FTRACE_INFO 0x00000010 + +/* DEPRECATED - please use "panic_console_replay" */ +#define PANIC_PRINT_ALL_PRINTK_MSG 0x00000020 + +#define PANIC_PRINT_ALL_CPU_BT 0x00000040 + +unsigned long panic_print; +bool panic_console_replay; + +static int panic_print_sys_info(struct notifier_block *self, + unsigned long ev, void *unused) +{ + if (panic_print & PANIC_PRINT_ALL_CPU_BT) + trigger_all_cpu_backtrace(); + + if (panic_print & PANIC_PRINT_TASK_INFO) + show_state(); + + if (panic_print & PANIC_PRINT_MEM_INFO) + show_mem(0, NULL); + + if (panic_print & PANIC_PRINT_TIMER_INFO) + sysrq_timer_list_show(); + + if (panic_print & PANIC_PRINT_LOCK_INFO) + debug_show_all_locks(); + + if (panic_print & PANIC_PRINT_FTRACE_INFO) + ftrace_dump(DUMP_ALL); + + /* + * This is legacy/deprecated feature from panic_print, + * the console force flushing. We have now the parameter + * "panic_console_replay", but we need to keep the + * retro-compatibility with the old stuff... + */ + if (panic_print & PANIC_PRINT_ALL_PRINTK_MSG) + panic_console_replay = true; + + return NOTIFY_DONE; +} + +static struct notifier_block panic_print_nb = { + .notifier_call = panic_print_sys_info, + .priority = INT_MIN, /* defer to run as late as possible */ +}; + +core_param(panic_print, panic_print, ulong, 0644); +core_param(panic_console_replay, panic_console_replay, bool, 0644); + /* * Some boot consoles access data that is in the init section and which will * be discarded after the initcalls have been run. To make sure that no code @@ -3253,6 +3309,12 @@ static int __init printk_late_init(void) struct console *con; int ret; + /* + * Register the panic notifier to print user information + * in case the user have that set. + */ + atomic_notifier_chain_register(&panic_info_list, &panic_print_nb); + for_each_console(con) { if (!(con->flags & CON_BOOT)) continue; -- 2.36.0