From 7d4ad47dc664a4d7004201002cc11cbdf7a2f7e7 Mon Sep 17 00:00:00 2001 From: Sonny Rao Date: Mon, 10 Dec 2012 11:06:02 -0800 Subject: [PATCH] CHROMIUM: sysrq: add ability for sysrq-x to signal chrome/X Because we weren't getting reports of actual kernel issues, and we've already trained some users to hit sysrq-x when the system appears to freeze, we decided to have sysrq-x try a few other things in addition to crashing the kernel. For the first keypress it will try to find the Chrome browser process, by looking for the one which has the session_manager as a parent, and send a SIGABRT to that. If there is a second sysrq-x within 5 seconds, it will send a SIGABRT to the X process, and if there's a third then it will crash the kernel as before. BUG=chromium-os:36901 TEST=manual (debugging feature): hold down alt-volup then x - chrome should crash repeat immediately afterward - session should restart repeat and machine should reboot Change-Id: I127256b7777aee4a4d84a958f2c061d7b6de318b Signed-off-by: Sonny Rao Reviewed-on: https://gerrit.chromium.org/gerrit/39527 Reviewed-by: Sameer Nanda Reviewed-by: Olof Johansson --- drivers/tty/sysrq.c | 68 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 4796af7c377a4..460998928668b 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -399,12 +399,72 @@ static struct sysrq_key_op sysrq_unrt_op = { .enable_mask = SYSRQ_ENABLE_RTNICE, }; +/* send a signal to a process named comm if it has a certain parent */ +/* if parent is NULL, send to the first matching process */ +static void sysrq_x_cros_signal_process(char *comm, char *parent, int sig) +{ + struct task_struct *p; + + read_lock(&tasklist_lock); + for_each_process(p) { + if (p->flags & PF_KTHREAD) + continue; + if (is_global_init(p)) + continue; + + if (!strncmp(p->comm, comm, TASK_COMM_LEN)) { + if (!parent) { + printk(KERN_INFO + "%s: signal %d %s pid %u tgid %u\n", + __func__, sig, comm, p->pid, p->tgid); + do_send_sig_info(sig, SEND_SIG_FORCED, p, + true); + break; + } else if (p->parent && + !strncmp(p->parent->comm, parent, + TASK_COMM_LEN)) { + printk(KERN_INFO + "%s: signal %d %s with parent %s " + "pid %u tgid %u\n", + __func__, sig, + comm, parent, p->parent->pid, + p->parent->tgid); + do_send_sig_info(sig, SEND_SIG_FORCED, p, + true); + break; + } + } + } + read_unlock(&tasklist_lock); +} + +/* how many seconds do we wait for subsequent keypresses after the first */ +#define CROS_SYSRQ_WAIT 20 + static void sysrq_handle_cros_xkey(int key) { - sysrq_handle_showstate_blocked(key); - sysrq_handle_sync(key); - mdelay(1000); /* Delay for a bit to give time for sync to complete */ - panic("ChromeOS X Key"); + static unsigned long first_jiffies; + static unsigned int xkey_iteration; + + if ((!first_jiffies) || + (jiffies - first_jiffies) > CROS_SYSRQ_WAIT * HZ) { + first_jiffies = jiffies; + xkey_iteration = 0; + } else + xkey_iteration++; + + if (!xkey_iteration) + sysrq_x_cros_signal_process("chrome", "session_manager", + SIGABRT); + else if (xkey_iteration == 1) + sysrq_x_cros_signal_process("X", NULL, SIGABRT); + else { + sysrq_handle_showstate_blocked(key); + sysrq_handle_sync(key); + /* Delay for a bit to give time for sync to complete */ + mdelay(1000); + panic("ChromeOS X Key"); + } } static struct sysrq_key_op sysrq_cros_xkey = { -- 2.39.5