diff options
Diffstat (limited to 'drivers/tty/sysrq.c')
-rw-r--r-- | drivers/tty/sysrq.c | 195 |
1 files changed, 130 insertions, 65 deletions
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index f724962a5906..d2b2720db6ca 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -19,6 +19,7 @@ #include <linux/sched/rt.h> #include <linux/sched/debug.h> #include <linux/sched/task.h> +#include <linux/ctype.h> #include <linux/interrupt.h> #include <linux/mm.h> #include <linux/fs.h> @@ -63,6 +64,19 @@ static bool sysrq_on(void) return sysrq_enabled || sysrq_always_enabled; } +/** + * sysrq_mask - Getter for sysrq_enabled mask. + * + * Return: 1 if sysrq is always enabled, enabled sysrq_key_op mask otherwise. + */ +int sysrq_mask(void) +{ + if (sysrq_always_enabled) + return 1; + return sysrq_enabled; +} +EXPORT_SYMBOL_GPL(sysrq_mask); + /* * A value of 1 means 'all', other nonzero values are an op mask: */ @@ -93,7 +107,7 @@ static void sysrq_handle_loglevel(int key) pr_info("Loglevel set to %d\n", i); console_loglevel = i; } -static struct sysrq_key_op sysrq_loglevel_op = { +static const struct sysrq_key_op sysrq_loglevel_op = { .handler = sysrq_handle_loglevel, .help_msg = "loglevel(0-9)", .action_msg = "Changing Loglevel", @@ -104,16 +118,17 @@ static struct sysrq_key_op sysrq_loglevel_op = { static void sysrq_handle_SAK(int key) { struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work; + schedule_work(SAK_work); } -static struct sysrq_key_op sysrq_SAK_op = { +static const struct sysrq_key_op sysrq_SAK_op = { .handler = sysrq_handle_SAK, .help_msg = "sak(k)", .action_msg = "SAK", .enable_mask = SYSRQ_ENABLE_KEYBOARD, }; #else -#define sysrq_SAK_op (*(struct sysrq_key_op *)NULL) +#define sysrq_SAK_op (*(const struct sysrq_key_op *)NULL) #endif #ifdef CONFIG_VT @@ -122,14 +137,14 @@ static void sysrq_handle_unraw(int key) vt_reset_unicode(fg_console); } -static struct sysrq_key_op sysrq_unraw_op = { +static const struct sysrq_key_op sysrq_unraw_op = { .handler = sysrq_handle_unraw, .help_msg = "unraw(r)", .action_msg = "Keyboard mode set to system default", .enable_mask = SYSRQ_ENABLE_KEYBOARD, }; #else -#define sysrq_unraw_op (*(struct sysrq_key_op *)NULL) +#define sysrq_unraw_op (*(const struct sysrq_key_op *)NULL) #endif /* CONFIG_VT */ static void sysrq_handle_crash(int key) @@ -139,7 +154,7 @@ static void sysrq_handle_crash(int key) panic("sysrq triggered crash\n"); } -static struct sysrq_key_op sysrq_crash_op = { +static const struct sysrq_key_op sysrq_crash_op = { .handler = sysrq_handle_crash, .help_msg = "crash(c)", .action_msg = "Trigger a crash", @@ -152,18 +167,20 @@ static void sysrq_handle_reboot(int key) local_irq_enable(); emergency_restart(); } -static struct sysrq_key_op sysrq_reboot_op = { +static const struct sysrq_key_op sysrq_reboot_op = { .handler = sysrq_handle_reboot, .help_msg = "reboot(b)", .action_msg = "Resetting", .enable_mask = SYSRQ_ENABLE_BOOT, }; +const struct sysrq_key_op *__sysrq_reboot_op = &sysrq_reboot_op; + static void sysrq_handle_sync(int key) { emergency_sync(); } -static struct sysrq_key_op sysrq_sync_op = { +static const struct sysrq_key_op sysrq_sync_op = { .handler = sysrq_handle_sync, .help_msg = "sync(s)", .action_msg = "Emergency Sync", @@ -175,7 +192,7 @@ static void sysrq_handle_show_timers(int key) sysrq_timer_list_show(); } -static struct sysrq_key_op sysrq_show_timers_op = { +static const struct sysrq_key_op sysrq_show_timers_op = { .handler = sysrq_handle_show_timers, .help_msg = "show-all-timers(q)", .action_msg = "Show clockevent devices & pending hrtimers (no others)", @@ -185,7 +202,7 @@ static void sysrq_handle_mountro(int key) { emergency_remount(); } -static struct sysrq_key_op sysrq_mountro_op = { +static const struct sysrq_key_op sysrq_mountro_op = { .handler = sysrq_handle_mountro, .help_msg = "unmount(u)", .action_msg = "Emergency Remount R/O", @@ -198,13 +215,13 @@ static void sysrq_handle_showlocks(int key) debug_show_all_locks(); } -static struct sysrq_key_op sysrq_showlocks_op = { +static const struct sysrq_key_op sysrq_showlocks_op = { .handler = sysrq_handle_showlocks, .help_msg = "show-all-locks(d)", .action_msg = "Show Locks Held", }; #else -#define sysrq_showlocks_op (*(struct sysrq_key_op *)NULL) +#define sysrq_showlocks_op (*(const struct sysrq_key_op *)NULL) #endif #ifdef CONFIG_SMP @@ -215,12 +232,14 @@ static void showacpu(void *dummy) unsigned long flags; /* Idle CPUs have no interesting backtrace. */ - if (idle_cpu(smp_processor_id())) + if (idle_cpu(smp_processor_id())) { + pr_info("CPU%d: backtrace skipped as idling\n", smp_processor_id()); return; + } raw_spin_lock_irqsave(&show_lock, flags); pr_info("CPU%d:\n", smp_processor_id()); - show_stack(NULL, NULL); + show_stack(NULL, NULL, KERN_INFO); raw_spin_unlock_irqrestore(&show_lock, flags); } @@ -241,35 +260,40 @@ static void sysrq_handle_showallcpus(int key) if (!trigger_all_cpu_backtrace()) { struct pt_regs *regs = NULL; - if (in_irq()) + if (in_hardirq()) regs = get_irq_regs(); - if (regs) { - pr_info("CPU%d:\n", smp_processor_id()); + + pr_info("CPU%d:\n", smp_processor_id()); + if (regs) show_regs(regs); - } + else + show_stack(NULL, NULL, KERN_INFO); + schedule_work(&sysrq_showallcpus); } } -static struct sysrq_key_op sysrq_showallcpus_op = { +static const struct sysrq_key_op sysrq_showallcpus_op = { .handler = sysrq_handle_showallcpus, .help_msg = "show-backtrace-all-active-cpus(l)", .action_msg = "Show backtrace of all active CPUs", .enable_mask = SYSRQ_ENABLE_DUMP, }; +#else +#define sysrq_showallcpus_op (*(const struct sysrq_key_op *)NULL) #endif static void sysrq_handle_showregs(int key) { struct pt_regs *regs = NULL; - if (in_irq()) + if (in_hardirq()) regs = get_irq_regs(); if (regs) show_regs(regs); perf_event_print_debug(); } -static struct sysrq_key_op sysrq_showregs_op = { +static const struct sysrq_key_op sysrq_showregs_op = { .handler = sysrq_handle_showregs, .help_msg = "show-registers(p)", .action_msg = "Show Regs", @@ -279,9 +303,9 @@ static struct sysrq_key_op sysrq_showregs_op = { static void sysrq_handle_showstate(int key) { show_state(); - show_workqueue_state(); + show_all_workqueues(); } -static struct sysrq_key_op sysrq_showstate_op = { +static const struct sysrq_key_op sysrq_showstate_op = { .handler = sysrq_handle_showstate, .help_msg = "show-task-states(t)", .action_msg = "Show State", @@ -292,7 +316,7 @@ static void sysrq_handle_showstate_blocked(int key) { show_state_filter(TASK_UNINTERRUPTIBLE); } -static struct sysrq_key_op sysrq_showstate_blocked_op = { +static const struct sysrq_key_op sysrq_showstate_blocked_op = { .handler = sysrq_handle_showstate_blocked, .help_msg = "show-blocked-tasks(w)", .action_msg = "Show Blocked State", @@ -306,21 +330,21 @@ static void sysrq_ftrace_dump(int key) { ftrace_dump(DUMP_ALL); } -static struct sysrq_key_op sysrq_ftrace_dump_op = { +static const struct sysrq_key_op sysrq_ftrace_dump_op = { .handler = sysrq_ftrace_dump, .help_msg = "dump-ftrace-buffer(z)", .action_msg = "Dump ftrace buffer", .enable_mask = SYSRQ_ENABLE_DUMP, }; #else -#define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)NULL) +#define sysrq_ftrace_dump_op (*(const struct sysrq_key_op *)NULL) #endif static void sysrq_handle_showmem(int key) { show_mem(0, NULL); } -static struct sysrq_key_op sysrq_showmem_op = { +static const struct sysrq_key_op sysrq_showmem_op = { .handler = sysrq_handle_showmem, .help_msg = "show-memory-usage(m)", .action_msg = "Show Memory", @@ -351,7 +375,7 @@ static void sysrq_handle_term(int key) send_sig_all(SIGTERM); console_loglevel = CONSOLE_LOGLEVEL_DEBUG; } -static struct sysrq_key_op sysrq_term_op = { +static const struct sysrq_key_op sysrq_term_op = { .handler = sysrq_handle_term, .help_msg = "terminate-all-tasks(e)", .action_msg = "Terminate All Tasks", @@ -381,7 +405,7 @@ static void sysrq_handle_moom(int key) { schedule_work(&moom_work); } -static struct sysrq_key_op sysrq_moom_op = { +static const struct sysrq_key_op sysrq_moom_op = { .handler = sysrq_handle_moom, .help_msg = "memory-full-oom-kill(f)", .action_msg = "Manual OOM execution", @@ -393,12 +417,14 @@ static void sysrq_handle_thaw(int key) { emergency_thaw_all(); } -static struct sysrq_key_op sysrq_thaw_op = { +static const struct sysrq_key_op sysrq_thaw_op = { .handler = sysrq_handle_thaw, .help_msg = "thaw-filesystems(j)", .action_msg = "Emergency Thaw of all frozen filesystems", .enable_mask = SYSRQ_ENABLE_SIGNAL, }; +#else +#define sysrq_thaw_op (*(const struct sysrq_key_op *)NULL) #endif static void sysrq_handle_kill(int key) @@ -406,7 +432,7 @@ static void sysrq_handle_kill(int key) send_sig_all(SIGKILL); console_loglevel = CONSOLE_LOGLEVEL_DEBUG; } -static struct sysrq_key_op sysrq_kill_op = { +static const struct sysrq_key_op sysrq_kill_op = { .handler = sysrq_handle_kill, .help_msg = "kill-all-tasks(i)", .action_msg = "Kill All Tasks", @@ -417,7 +443,7 @@ static void sysrq_handle_unrt(int key) { normalize_rt_tasks(); } -static struct sysrq_key_op sysrq_unrt_op = { +static const struct sysrq_key_op sysrq_unrt_op = { .handler = sysrq_handle_unrt, .help_msg = "nice-all-RT-tasks(n)", .action_msg = "Nice All RT Tasks", @@ -427,7 +453,7 @@ static struct sysrq_key_op sysrq_unrt_op = { /* Key Operations table and lock */ static DEFINE_SPINLOCK(sysrq_key_table_lock); -static struct sysrq_key_op *sysrq_key_table[36] = { +static const struct sysrq_key_op *sysrq_key_table[62] = { &sysrq_loglevel_op, /* 0 */ &sysrq_loglevel_op, /* 1 */ &sysrq_loglevel_op, /* 2 */ @@ -453,17 +479,9 @@ static struct sysrq_key_op *sysrq_key_table[36] = { NULL, /* g */ NULL, /* h - reserved for help */ &sysrq_kill_op, /* i */ -#ifdef CONFIG_BLOCK &sysrq_thaw_op, /* j */ -#else - NULL, /* j */ -#endif &sysrq_SAK_op, /* k */ -#ifdef CONFIG_SMP &sysrq_showallcpus_op, /* l */ -#else - NULL, /* l */ -#endif &sysrq_showmem_op, /* m */ &sysrq_unrt_op, /* n */ /* o: This will often be registered as 'Off' at init time */ @@ -484,6 +502,32 @@ static struct sysrq_key_op *sysrq_key_table[36] = { /* y: May be registered on sparc64 for global register dump */ NULL, /* y */ &sysrq_ftrace_dump_op, /* z */ + NULL, /* A */ + NULL, /* B */ + NULL, /* C */ + NULL, /* D */ + NULL, /* E */ + NULL, /* F */ + NULL, /* G */ + NULL, /* H */ + NULL, /* I */ + NULL, /* J */ + NULL, /* K */ + NULL, /* L */ + NULL, /* M */ + NULL, /* N */ + NULL, /* O */ + NULL, /* P */ + NULL, /* Q */ + NULL, /* R */ + NULL, /* S */ + NULL, /* T */ + NULL, /* U */ + NULL, /* V */ + NULL, /* W */ + NULL, /* X */ + NULL, /* Y */ + NULL, /* Z */ }; /* key2index calculation, -1 on invalid index */ @@ -495,6 +539,8 @@ static int sysrq_key_table_key2index(int key) retval = key - '0'; else if ((key >= 'a') && (key <= 'z')) retval = key + 10 - 'a'; + else if ((key >= 'A') && (key <= 'Z')) + retval = key + 36 - 'A'; else retval = -1; return retval; @@ -503,29 +549,29 @@ static int sysrq_key_table_key2index(int key) /* * get and put functions for the table, exposed to modules. */ -struct sysrq_key_op *__sysrq_get_key_op(int key) +static const struct sysrq_key_op *__sysrq_get_key_op(int key) { - struct sysrq_key_op *op_p = NULL; - int i; + const struct sysrq_key_op *op_p = NULL; + int i; i = sysrq_key_table_key2index(key); if (i != -1) - op_p = sysrq_key_table[i]; + op_p = sysrq_key_table[i]; - return op_p; + return op_p; } -static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p) +static void __sysrq_put_key_op(int key, const struct sysrq_key_op *op_p) { - int i = sysrq_key_table_key2index(key); + int i = sysrq_key_table_key2index(key); - if (i != -1) - sysrq_key_table[i] = op_p; + if (i != -1) + sysrq_key_table[i] = op_p; } void __handle_sysrq(int key, bool check_mask) { - struct sysrq_key_op *op_p; + const struct sysrq_key_op *op_p; int orig_log_level; int orig_suppress_printk; int i; @@ -544,8 +590,8 @@ void __handle_sysrq(int key, bool check_mask) orig_log_level = console_loglevel; console_loglevel = CONSOLE_LOGLEVEL_DEFAULT; - op_p = __sysrq_get_key_op(key); - if (op_p) { + op_p = __sysrq_get_key_op(key); + if (op_p) { /* * Should we check for enabled operations (/proc/sysrq-trigger * should not) and is the invoked operation enabled? @@ -594,13 +640,13 @@ static int sysrq_reset_downtime_ms; /* Simple translation table for the SysRq keys */ static const unsigned char sysrq_xlate[KEY_CNT] = - "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ - "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ - "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ - "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ - "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ - "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ - "\r\000/"; /* 0x60 - 0x6f */ + "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ + "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ + "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ + "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ + "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ + "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ + "\r\000/"; /* 0x60 - 0x6f */ struct sysrq_state { struct input_handle handle; @@ -608,6 +654,8 @@ struct sysrq_state { unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; unsigned int alt; unsigned int alt_use; + unsigned int shift; + unsigned int shift_use; bool active; bool need_reinject; bool reinjecting; @@ -792,10 +840,22 @@ static bool sysrq_handle_keypress(struct sysrq_state *sysrq, } break; + case KEY_LEFTSHIFT: + case KEY_RIGHTSHIFT: + if (!value) + sysrq->shift = KEY_RESERVED; + else if (value != 2) + sysrq->shift = code; + if (sysrq->active) + sysrq->shift_use = sysrq->shift; + break; + case KEY_SYSRQ: if (value == 1 && sysrq->alt != KEY_RESERVED) { sysrq->active = true; sysrq->alt_use = sysrq->alt; + /* either RESERVED (for released) or actual code */ + sysrq->shift_use = sysrq->shift; /* * If nothing else will be pressed we'll need * to re-inject Alt-SysRq keysroke. @@ -818,8 +878,12 @@ static bool sysrq_handle_keypress(struct sysrq_state *sysrq, default: if (sysrq->active && value && value != 2) { + unsigned char c = sysrq_xlate[code]; + sysrq->need_reinject = false; - __handle_sysrq(sysrq_xlate[code], true); + if (sysrq->shift_use != KEY_RESERVED) + c = toupper(c); + __handle_sysrq(c, true); } break; } @@ -1046,9 +1110,10 @@ int sysrq_toggle_support(int enable_mask) return 0; } +EXPORT_SYMBOL_GPL(sysrq_toggle_support); -static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p, - struct sysrq_key_op *remove_op_p) +static int __sysrq_swap_key_ops(int key, const struct sysrq_key_op *insert_op_p, + const struct sysrq_key_op *remove_op_p) { int retval; @@ -1071,13 +1136,13 @@ static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p, return retval; } -int register_sysrq_key(int key, struct sysrq_key_op *op_p) +int register_sysrq_key(int key, const struct sysrq_key_op *op_p) { return __sysrq_swap_key_ops(key, op_p, NULL); } EXPORT_SYMBOL(register_sysrq_key); -int unregister_sysrq_key(int key, struct sysrq_key_op *op_p) +int unregister_sysrq_key(int key, const struct sysrq_key_op *op_p) { return __sysrq_swap_key_ops(key, NULL, op_p); } |