When terminal is unresponsive, one cannot use dmesg to view kernel ring buffer messages. Also, syslog services may be disabled, to check them after a reboot, especially on embedded systems. In this scenario, dump the kernel ring buffer messages via sysrq by pressing sysrq+D. Signed-off-by: Sreenath Vijayan <sreenath.vijayan@xxxxxxxx> Signed-off-by: Shimoyashiki Taichi <taichi.shimoyashiki@xxxxxxxx> --- Documentation/admin-guide/sysrq.rst | 2 ++ drivers/tty/sysrq.c | 43 ++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/sysrq.rst b/Documentation/admin-guide/sysrq.rst index 2f2e5bd440f9..464c4e138b9d 100644 --- a/Documentation/admin-guide/sysrq.rst +++ b/Documentation/admin-guide/sysrq.rst @@ -161,6 +161,8 @@ Command Function will be printed to your console. (``0``, for example would make it so that only emergency messages like PANICs or OOPSes would make it to your console.) + +``D`` Dump the kernel ring buffer =========== =================================================================== Okay, so what can I use them for? diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 02217e3c916b..aa43cb40c117 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -51,6 +51,8 @@ #include <linux/syscalls.h> #include <linux/of.h> #include <linux/rcupdate.h> +#include <linux/kmsg_dump.h> +#include <linux/console.h> #include <asm/ptrace.h> #include <asm/irq_regs.h> @@ -450,6 +452,45 @@ static const struct sysrq_key_op sysrq_unrt_op = { .enable_mask = SYSRQ_ENABLE_RTNICE, }; +static void dmesg_dump_callback(struct work_struct *work) +{ + struct kmsg_dump_iter iter; + size_t len; + char buf[1024]; + struct console *con; + int cookie; + + kmsg_dump_rewind(&iter); + while (kmsg_dump_get_line(&iter, 1, buf, sizeof(buf), &len)) { + /* + * Since using printk() or pr_*() will append the message to the + * kernel ring buffer, they cannot be used to display the retrieved + * message. Hence console_write() of serial drivers is used. + */ + console_lock(); + cookie = console_srcu_read_lock(); + for_each_console_srcu(con) { + if ((console_srcu_read_flags(con) & CON_ENABLED) && con->write) + con->write(con, buf, len); + } + console_srcu_read_unlock(cookie); + console_unlock(); + } +} + +static DECLARE_WORK(sysrq_dmesg_work, dmesg_dump_callback); + +static void sysrq_handle_dmesg_dump(u8 key) +{ + queue_work(system_unbound_wq, &sysrq_dmesg_work); +} +static struct sysrq_key_op sysrq_dmesg_dump_op = { + .handler = sysrq_handle_dmesg_dump, + .help_msg = "dump-dmesg(D)", + .action_msg = "Dump dmesg", + .enable_mask = SYSRQ_ENABLE_DUMP, +}; + /* Key Operations table and lock */ static DEFINE_SPINLOCK(sysrq_key_table_lock); @@ -505,7 +546,7 @@ static const struct sysrq_key_op *sysrq_key_table[62] = { NULL, /* A */ NULL, /* B */ NULL, /* C */ - NULL, /* D */ + &sysrq_dmesg_dump_op, /* D */ NULL, /* E */ NULL, /* F */ NULL, /* G */ -- 2.42.0