From 177435e2ea71dd66b838d02b4de58f79babf903c Mon Sep 17 00:00:00 2001 From: Tao Huang Date: Tue, 14 Nov 2017 15:02:57 +0800 Subject: [PATCH] pstore/console: ignore log level When printk to pstore console, we ignore log level. So /sys/fs/pstore/console-ramoops-0 should keep full kernel log. This feature enabled with the bool parameter pstore_con_force. Change-Id: I87ea3418741c117523a9e872ae7ace4dac0cd9d3 Signed-off-by: Tao Huang --- fs/pstore/Kconfig | 12 ++++++++ fs/pstore/platform.c | 4 +++ include/linux/console.h | 3 ++ kernel/printk/printk.c | 66 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+) diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig index 503086f7f7c1..29943657db25 100644 --- a/fs/pstore/Kconfig +++ b/fs/pstore/Kconfig @@ -114,6 +114,18 @@ config PSTORE_CONSOLE When the option is enabled, pstore will log all kernel messages, even if no oops or panic happened. +config PSTORE_CONSOLE_FORCE + bool "Log kernel console messages ignore loglevel setting" + depends on PSTORE_CONSOLE + help + When the option is enabled, allow all kernel messages + log to the pstore console. Enable this with a kernel bool + parameter like "pstore_con_force=1". + +config PSTORE_CONSOLE_FORCE_ON + bool "Log kernel console messages ignore loglevel setting on by default" + depends on PSTORE_CONSOLE_FORCE + config PSTORE_PMSG bool "Log user space messages" depends on PSTORE diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 4bae3f4fe829..5d089def0436 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -492,7 +492,11 @@ static void pstore_console_write(struct console *con, const char *s, unsigned c) static struct console pstore_console = { .name = "pstore", .write = pstore_console_write, +#ifdef CON_PSTORE + .flags = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME | CON_PSTORE, +#else .flags = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME, +#endif .index = -1, }; diff --git a/include/linux/console.h b/include/linux/console.h index ec9bdb3d7bab..cce6e719a03f 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -141,6 +141,9 @@ static inline int con_debug_leave(void) #define CON_ANYTIME (16) /* Safe to call when cpu is offline */ #define CON_BRL (32) /* Used for a braille device */ #define CON_EXTENDED (64) /* Use the extended output format a la /dev/kmsg */ +#ifdef CONFIG_PSTORE_CONSOLE_FORCE +#define CON_PSTORE (128) /* Print to pstore console anyway */ +#endif struct console { char name[16]; diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 51904f47f874..6e21a88b1a9a 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1200,7 +1200,11 @@ void __init setup_log_buf(int early) free, (free * 100) / __LOG_BUF_LEN); } +#ifdef CONFIG_PSTORE_CONSOLE_FORCE_ON +static bool __read_mostly ignore_loglevel = true; +#else static bool __read_mostly ignore_loglevel; +#endif static int __init ignore_loglevel_setup(char *str) { @@ -1215,6 +1219,61 @@ module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ignore_loglevel, "ignore loglevel setting (prints all kernel messages to the console)"); +#ifdef CONFIG_PSTORE_CONSOLE_FORCE +static bool __read_mostly pstore_con_force = IS_ENABLED(CONFIG_PSTORE_CONSOLE_FORCE_ON); + +static int __init pstore_con_force_setup(char *str) +{ + bool force; + int ret = strtobool(str, &force); + + if (ret) + return ret; + + ignore_loglevel = force; + pstore_con_force = force; + if (force) + pr_info("debug: pstore console ignoring loglevel setting.\n"); + + return 0; +} + +early_param("pstore_con_force", pstore_con_force_setup); +module_param(pstore_con_force, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(pstore_con_force, + "ignore loglevel setting (prints all kernel messages to the pstore console)"); + +static void call_console_drivers_level(int level, const char *ext_text, size_t ext_len, + const char *text, size_t len) +{ + struct console *con; + + trace_console_rcuidle(text, len); + + if (!console_drivers) + return; + + for_each_console(con) { + if (pstore_con_force && + !(con->flags & CON_PSTORE) && level >= console_loglevel) + continue; + if (exclusive_console && con != exclusive_console) + continue; + if (!(con->flags & CON_ENABLED)) + continue; + if (!con->write) + continue; + if (!cpu_online(smp_processor_id()) && + !(con->flags & CON_ANYTIME)) + continue; + if (con->flags & CON_EXTENDED) + con->write(con, ext_text, ext_len); + else + con->write(con, text, len); + } +} +#endif + static bool suppress_message_printing(int level) { return (level >= console_loglevel && !ignore_loglevel); @@ -1770,6 +1829,9 @@ static int console_trylock_spinning(void) * log_buf[start] to log_buf[end - 1]. * The console_lock must be held. */ +#ifdef CONFIG_PSTORE_CONSOLE_FORCE +__maybe_unused +#endif static void call_console_drivers(const char *ext_text, size_t ext_len, const char *text, size_t len) { @@ -2486,7 +2548,11 @@ skip: console_lock_spinning_enable(); stop_critical_timings(); /* don't trace print latency */ +#ifdef CONFIG_PSTORE_CONSOLE_FORCE + call_console_drivers_level(msg->level, ext_text, ext_len, text, len); +#else call_console_drivers(ext_text, ext_len, text, len); +#endif start_critical_timings(); if (console_lock_spinning_disable_and_check()) {