X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fchar%2Fsysrq.c;h=5ce41aebe7e642afaec91fafe365d9b5a0fe89b7;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=d58f823188539651f6e6eabd76ac091cae7f835b;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index d58f82318..5ce41aebe 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -12,7 +12,6 @@ * based upon discusions in irc://irc.openprojects.net/#kernelnewbies */ -#include #include #include #include @@ -36,22 +35,50 @@ #include #include #include +#include +#include #include +#include /* Whether we react on sysrq keys or just ignore them */ -int sysrq_enabled = 1; +int __read_mostly __sysrq_enabled = 1; -/* Loglevel sysrq handler */ -static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static int __read_mostly sysrq_always_enabled; + +int sysrq_on(void) +{ + return __sysrq_enabled || sysrq_always_enabled; +} + +/* + * A value of 1 means 'all', other nonzero values are an op mask: + */ +static inline int sysrq_on_mask(int mask) +{ + return sysrq_always_enabled || __sysrq_enabled == 1 || + (__sysrq_enabled & mask); +} + +static int __init sysrq_always_enabled_setup(char *str) +{ + sysrq_always_enabled = 1; + printk(KERN_INFO "debug: sysrq always enabled.\n"); + + return 1; +} + +__setup("sysrq_always_enabled", sysrq_always_enabled_setup); + + +static void sysrq_handle_loglevel(int key, struct tty_struct *tty) { int i; i = key - '0'; console_loglevel = 7; printk("Loglevel set to %d\n", i); console_loglevel = i; -} +} static struct sysrq_key_op sysrq_loglevel_op = { .handler = sysrq_handle_loglevel, .help_msg = "loglevel0-8", @@ -59,11 +86,8 @@ static struct sysrq_key_op sysrq_loglevel_op = { .enable_mask = SYSRQ_ENABLE_LOG, }; - -/* SAK sysrq handler */ #ifdef CONFIG_VT -static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_SAK(int key, struct tty_struct *tty) { if (tty) do_SAK(tty); @@ -75,12 +99,12 @@ static struct sysrq_key_op sysrq_SAK_op = { .action_msg = "SAK", .enable_mask = SYSRQ_ENABLE_KEYBOARD, }; +#else +#define sysrq_SAK_op (*(struct sysrq_key_op *)0) #endif #ifdef CONFIG_VT -/* unraw sysrq handler */ -static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_unraw(int key, struct tty_struct *tty) { struct kbd_struct *kbd = &kbd_table[fg_console]; @@ -93,14 +117,19 @@ static struct sysrq_key_op sysrq_unraw_op = { .action_msg = "Keyboard mode set to XLATE", .enable_mask = SYSRQ_ENABLE_KEYBOARD, }; +#else +#define sysrq_unraw_op (*(struct sysrq_key_op *)0) #endif /* CONFIG_VT */ -#ifdef CONFIG_KEXEC -/* crashdump sysrq handler */ -static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_crashdump(int key, struct tty_struct *tty) { - crash_kexec(pt_regs); +#ifdef CONFIG_KEXEC + crash_kexec(get_irq_regs()); + /* can't get here if crash image is loaded */ + printk("Kexec: Warning: crash image not loaded\n"); +#endif + if (panic_on_oops) + panic("SysRq-triggered panic!\n"); } static struct sysrq_key_op sysrq_crashdump_op = { .handler = sysrq_handle_crashdump, @@ -108,16 +137,13 @@ static struct sysrq_key_op sysrq_crashdump_op = { .action_msg = "Trigger a crashdump", .enable_mask = SYSRQ_ENABLE_DUMP, }; -#endif -/* reboot sysrq handler */ -static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_reboot(int key, struct tty_struct *tty) { + lockdep_off(); local_irq_enable(); emergency_restart(); } - static struct sysrq_key_op sysrq_reboot_op = { .handler = sysrq_handle_reboot, .help_msg = "reBoot", @@ -125,12 +151,10 @@ static struct sysrq_key_op sysrq_reboot_op = { .enable_mask = SYSRQ_ENABLE_BOOT, }; -static void sysrq_handle_sync(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_sync(int key, struct tty_struct *tty) { emergency_sync(); } - static struct sysrq_key_op sysrq_sync_op = { .handler = sysrq_handle_sync, .help_msg = "Sync", @@ -138,12 +162,10 @@ static struct sysrq_key_op sysrq_sync_op = { .enable_mask = SYSRQ_ENABLE_SYNC, }; -static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_mountro(int key, struct tty_struct *tty) { emergency_remount(); } - static struct sysrq_key_op sysrq_mountro_op = { .handler = sysrq_handle_mountro, .help_msg = "Unmount", @@ -151,14 +173,10 @@ static struct sysrq_key_op sysrq_mountro_op = { .enable_mask = SYSRQ_ENABLE_REMOUNT, }; -/* END SYNC SYSRQ HANDLERS BLOCK */ - -#ifdef CONFIG_DEBUG_MUTEXES - -static void -sysrq_handle_showlocks(int key, struct pt_regs *pt_regs, struct tty_struct *tty) +#ifdef CONFIG_LOCKDEP +static void sysrq_handle_showlocks(int key, struct tty_struct *tty) { - mutex_debug_show_all_locks(); + debug_show_all_locks(); } static struct sysrq_key_op sysrq_showlocks_op = { @@ -166,16 +184,15 @@ static struct sysrq_key_op sysrq_showlocks_op = { .help_msg = "show-all-locks(D)", .action_msg = "Show Locks Held", }; - +#else +#define sysrq_showlocks_op (*(struct sysrq_key_op *)0) #endif -/* SHOW SYSRQ HANDLERS BLOCK */ - -static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_showregs(int key, struct tty_struct *tty) { - if (pt_regs) - show_regs(pt_regs); + struct pt_regs *regs = get_irq_regs(); + if (regs) + show_regs(regs); } static struct sysrq_key_op sysrq_showregs_op = { .handler = sysrq_handle_showregs, @@ -184,9 +201,7 @@ static struct sysrq_key_op sysrq_showregs_op = { .enable_mask = SYSRQ_ENABLE_DUMP, }; - -static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_showstate(int key, struct tty_struct *tty) { show_state(); } @@ -197,9 +212,19 @@ static struct sysrq_key_op sysrq_showstate_op = { .enable_mask = SYSRQ_ENABLE_DUMP, }; +static void sysrq_handle_showstate_blocked(int key, struct tty_struct *tty) +{ + show_state_filter(TASK_UNINTERRUPTIBLE); +} +static struct sysrq_key_op sysrq_showstate_blocked_op = { + .handler = sysrq_handle_showstate_blocked, + .help_msg = "shoW-blocked-tasks", + .action_msg = "Show Blocked State", + .enable_mask = SYSRQ_ENABLE_DUMP, +}; + -static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_showmem(int key, struct tty_struct *tty) { show_mem(); } @@ -210,26 +235,21 @@ static struct sysrq_key_op sysrq_showmem_op = { .enable_mask = SYSRQ_ENABLE_DUMP, }; -/* SHOW SYSRQ HANDLERS BLOCK */ - - -/* SIGNAL SYSRQ HANDLERS BLOCK */ - -/* signal sysrq helper function - * Sends a signal to all user processes */ +/* + * Signal sysrq helper function. Sends a signal to all user processes. + */ static void send_sig_all(int sig) { struct task_struct *p; for_each_process(p) { - if (p->mm && p->pid != 1) + if (p->mm && !is_init(p)) /* Not swapper, init nor kernel thread */ force_sig(sig, p); } } -static void sysrq_handle_term(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_term(int key, struct tty_struct *tty) { send_sig_all(SIGTERM); console_loglevel = 8; @@ -241,15 +261,15 @@ static struct sysrq_key_op sysrq_term_op = { .enable_mask = SYSRQ_ENABLE_SIGNAL, }; -static void moom_callback(void *ignored) +static void moom_callback(struct work_struct *ignored) { - out_of_memory(&NODE_DATA(0)->node_zonelists[ZONE_NORMAL], GFP_KERNEL, 0); + out_of_memory(&NODE_DATA(0)->node_zonelists[ZONE_NORMAL], + GFP_KERNEL, 0); } -static DECLARE_WORK(moom_work, moom_callback, NULL); +static DECLARE_WORK(moom_work, moom_callback); -static void sysrq_handle_moom(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_moom(int key, struct tty_struct *tty) { schedule_work(&moom_work); } @@ -259,8 +279,7 @@ static struct sysrq_key_op sysrq_moom_op = { .action_msg = "Manual OOM execution", }; -static void sysrq_handle_kill(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_kill(int key, struct tty_struct *tty) { send_sig_all(SIGKILL); console_loglevel = 8; @@ -272,10 +291,7 @@ static struct sysrq_key_op sysrq_kill_op = { .enable_mask = SYSRQ_ENABLE_SIGNAL, }; -/* END SIGNAL SYSRQ HANDLERS BLOCK */ - -static void sysrq_handle_unrt(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) +static void sysrq_handle_unrt(int key, struct tty_struct *tty) { normalize_rt_tasks(); } @@ -286,112 +302,123 @@ static struct sysrq_key_op sysrq_unrt_op = { .enable_mask = SYSRQ_ENABLE_RTNICE, }; + +#ifdef CONFIG_VSERVER_DEBUG +static void sysrq_handle_vxinfo(int key, struct tty_struct *tty) +{ + dump_vx_info_inactive((key == 'x')?0:1); +} + +static struct sysrq_key_op sysrq_showvxinfo_op = { + .handler = sysrq_handle_vxinfo, + .help_msg = "conteXt", + .action_msg = "Show Context Info", + .enable_mask = SYSRQ_ENABLE_DUMP, +}; +#endif + /* Key Operations table and lock */ static DEFINE_SPINLOCK(sysrq_key_table_lock); -#define SYSRQ_KEY_TABLE_LENGTH 36 -static struct sysrq_key_op *sysrq_key_table[SYSRQ_KEY_TABLE_LENGTH] = { -/* 0 */ &sysrq_loglevel_op, -/* 1 */ &sysrq_loglevel_op, -/* 2 */ &sysrq_loglevel_op, -/* 3 */ &sysrq_loglevel_op, -/* 4 */ &sysrq_loglevel_op, -/* 5 */ &sysrq_loglevel_op, -/* 6 */ &sysrq_loglevel_op, -/* 7 */ &sysrq_loglevel_op, -/* 8 */ &sysrq_loglevel_op, -/* 9 */ &sysrq_loglevel_op, -/* a */ NULL, /* Don't use for system provided sysrqs, - it is handled specially on the sparc - and will never arrive */ -/* b */ &sysrq_reboot_op, -#ifdef CONFIG_KEXEC -/* c */ &sysrq_crashdump_op, -#else -/* c */ NULL, -#endif -#ifdef CONFIG_DEBUG_MUTEXES -/* d */ &sysrq_showlocks_op, -#else -/* d */ NULL, -#endif -/* e */ &sysrq_term_op, -/* f */ &sysrq_moom_op, -/* g */ NULL, -/* h */ NULL, -/* i */ &sysrq_kill_op, -/* j */ NULL, -#ifdef CONFIG_VT -/* k */ &sysrq_SAK_op, -#else -/* k */ NULL, -#endif -/* l */ NULL, -/* m */ &sysrq_showmem_op, -/* n */ &sysrq_unrt_op, -/* o */ NULL, /* This will often be registered - as 'Off' at init time */ -/* p */ &sysrq_showregs_op, -/* q */ NULL, -#ifdef CONFIG_VT -/* r */ &sysrq_unraw_op, + +static struct sysrq_key_op *sysrq_key_table[36] = { + &sysrq_loglevel_op, /* 0 */ + &sysrq_loglevel_op, /* 1 */ + &sysrq_loglevel_op, /* 2 */ + &sysrq_loglevel_op, /* 3 */ + &sysrq_loglevel_op, /* 4 */ + &sysrq_loglevel_op, /* 5 */ + &sysrq_loglevel_op, /* 6 */ + &sysrq_loglevel_op, /* 7 */ + &sysrq_loglevel_op, /* 8 */ + &sysrq_loglevel_op, /* 9 */ + + /* + * a: Don't use for system provided sysrqs, it is handled specially on + * sparc and will never arrive. + */ + NULL, /* a */ + &sysrq_reboot_op, /* b */ + &sysrq_crashdump_op, /* c & ibm_emac driver debug */ + &sysrq_showlocks_op, /* d */ + &sysrq_term_op, /* e */ + &sysrq_moom_op, /* f */ + /* g: May be registered by ppc for kgdb */ + NULL, /* g */ + NULL, /* h */ + &sysrq_kill_op, /* i */ + NULL, /* j */ + &sysrq_SAK_op, /* k */ + NULL, /* l */ + &sysrq_showmem_op, /* m */ + &sysrq_unrt_op, /* n */ + /* o: This will often be registered as 'Off' at init time */ + NULL, /* o */ + &sysrq_showregs_op, /* p */ + NULL, /* q */ + &sysrq_unraw_op, /* r */ + &sysrq_sync_op, /* s */ + &sysrq_showstate_op, /* t */ + &sysrq_mountro_op, /* u */ + /* v: May be registered at init time by SMP VOYAGER */ + NULL, /* v */ + &sysrq_showstate_blocked_op, /* w */ + /* x: May be registered on ppc/powerpc for xmon */ + NULL, /* x */ + NULL, /* y */ +#ifdef CONFIG_VSERVER_DEBUG + &sysrq_showvxinfo_op, /* z */ #else -/* r */ NULL, + NULL, /* z */ #endif -/* s */ &sysrq_sync_op, -/* t */ &sysrq_showstate_op, -/* u */ &sysrq_mountro_op, -/* v */ NULL, /* May be assigned at init time by SMP VOYAGER */ -/* w */ NULL, -/* x */ NULL, -/* y */ NULL, -/* z */ NULL }; /* key2index calculation, -1 on invalid index */ -static int sysrq_key_table_key2index(int key) { +static int sysrq_key_table_key2index(int key) +{ int retval; - if ((key >= '0') && (key <= '9')) { + + if ((key >= '0') && (key <= '9')) retval = key - '0'; - } else if ((key >= 'a') && (key <= 'z')) { + else if ((key >= 'a') && (key <= 'z')) retval = key + 10 - 'a'; - } else { + else if ((key >= 'A') && (key <= 'Z')) + retval = key + 10 - 'A'; + else retval = -1; - } return retval; } /* * get and put functions for the table, exposed to modules. */ - -struct sysrq_key_op *__sysrq_get_key_op (int key) { - struct sysrq_key_op *op_p; +struct sysrq_key_op *__sysrq_get_key_op(int key) +{ + struct sysrq_key_op *op_p = NULL; int i; - + i = sysrq_key_table_key2index(key); - op_p = (i == -1) ? NULL : sysrq_key_table[i]; + if (i != -1) + op_p = sysrq_key_table[i]; return op_p; } -static void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) { - int i; +static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p) +{ + int i = sysrq_key_table_key2index(key); - i = sysrq_key_table_key2index(key); if (i != -1) sysrq_key_table[i] = op_p; } /* - * This is the non-locking version of handle_sysrq - * It must/can only be called by sysrq key handlers, - * as they are inside of the lock + * This is the non-locking version of handle_sysrq. It must/can only be called + * by sysrq key handlers, as they are inside of the lock */ - -void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty, int check_mask) +void __handle_sysrq(int key, struct tty_struct *tty, int check_mask) { struct sysrq_key_op *op_p; int orig_log_level; - int i, j; + int i; unsigned long flags; spin_lock_irqsave(&sysrq_key_table_lock, flags); @@ -401,26 +428,33 @@ void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty, in 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? */ - if (!check_mask || sysrq_enabled == 1 || - (sysrq_enabled & op_p->enable_mask)) { - printk ("%s\n", op_p->action_msg); + /* + * Should we check for enabled operations (/proc/sysrq-trigger + * should not) and is the invoked operation enabled? + */ + if (!check_mask || sysrq_on_mask(op_p->enable_mask)) { + printk("%s\n", op_p->action_msg); console_loglevel = orig_log_level; - op_p->handler(key, pt_regs, tty); - } - else + op_p->handler(key, tty); + } else { printk("This sysrq operation is disabled.\n"); + } } else { printk("HELP : "); /* Only print the help msg once per handler */ - for (i=0; ihelp_msg); + for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) { + if (sysrq_key_table[i]) { + int j; + + for (j = 0; sysrq_key_table[i] != + sysrq_key_table[j]; j++) + ; + if (j != i) + continue; + printk("%s ", sysrq_key_table[i]->help_msg); + } } - printk ("\n"); + printk("\n"); console_loglevel = orig_log_level; } spin_unlock_irqrestore(&sysrq_key_table_lock, flags); @@ -430,16 +464,16 @@ void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty, in * This function is called by the keyboard handler when SysRq is pressed * and any other keycode arrives. */ - -void handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty) +void handle_sysrq(int key, struct tty_struct *tty) { - if (!sysrq_enabled) - return; - __handle_sysrq(key, pt_regs, tty, 1); + if (sysrq_on()) + __handle_sysrq(key, tty, 1); } +EXPORT_SYMBOL(handle_sysrq); static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p, - struct sysrq_key_op *remove_op_p) { + struct sysrq_key_op *remove_op_p) +{ int retval; unsigned long flags; @@ -452,7 +486,6 @@ static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p, retval = -1; } spin_unlock_irqrestore(&sysrq_key_table_lock, flags); - return retval; } @@ -460,12 +493,10 @@ int register_sysrq_key(int key, 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) { return __sysrq_swap_key_ops(key, NULL, op_p); } - -EXPORT_SYMBOL(handle_sysrq); -EXPORT_SYMBOL(register_sysrq_key); EXPORT_SYMBOL(unregister_sysrq_key);