#include <linux/suspend.h>
#include <linux/writeback.h>
#include <linux/buffer_head.h> /* for fsync_bdev() */
-
+#include <linux/swap.h>
#include <linux/spinlock.h>
+#include <linux/vt_kern.h>
+#include <linux/workqueue.h>
+#include <linux/kexec.h>
#include <asm/ptrace.h>
-extern void reset_vc(unsigned int);
-
/* Whether we react on sysrq keys or just ignore them */
int sysrq_enabled = 1;
-/* Machine specific power off function */
-void (*sysrq_power_off)(void);
-
/* Loglevel sysrq handler */
static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs,
struct tty_struct *tty)
.handler = sysrq_handle_loglevel,
.help_msg = "loglevel0-8",
.action_msg = "Changing Loglevel",
+ .enable_mask = SYSRQ_ENABLE_LOG,
};
{
if (tty)
do_SAK(tty);
- reset_vc(fg_console);
+ reset_vc(vc_cons[fg_console].d);
}
static struct sysrq_key_op sysrq_SAK_op = {
.handler = sysrq_handle_SAK,
.help_msg = "saK",
.action_msg = "SAK",
+ .enable_mask = SYSRQ_ENABLE_KEYBOARD,
};
#endif
.handler = sysrq_handle_unraw,
.help_msg = "unRaw",
.action_msg = "Keyboard mode set to XLATE",
+ .enable_mask = SYSRQ_ENABLE_KEYBOARD,
};
#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)
+{
+ crash_kexec(pt_regs);
+}
+static struct sysrq_key_op sysrq_crashdump_op = {
+ .handler = sysrq_handle_crashdump,
+ .help_msg = "Crashdump",
+ .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)
{
- machine_restart(NULL);
+ local_irq_enable();
+ emergency_restart();
}
static struct sysrq_key_op sysrq_reboot_op = {
.handler = sysrq_handle_reboot,
.help_msg = "reBoot",
.action_msg = "Resetting",
+ .enable_mask = SYSRQ_ENABLE_BOOT,
};
static void sysrq_handle_sync(int key, struct pt_regs *pt_regs,
.handler = sysrq_handle_sync,
.help_msg = "Sync",
.action_msg = "Emergency Sync",
+ .enable_mask = SYSRQ_ENABLE_SYNC,
};
static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs,
.handler = sysrq_handle_mountro,
.help_msg = "Unmount",
.action_msg = "Emergency Remount R/O",
+ .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)
+{
+ mutex_debug_show_all_locks();
+}
+
+static struct sysrq_key_op sysrq_showlocks_op = {
+ .handler = sysrq_handle_showlocks,
+ .help_msg = "show-all-locks(D)",
+ .action_msg = "Show Locks Held",
+};
+
+#endif
/* SHOW SYSRQ HANDLERS BLOCK */
.handler = sysrq_handle_showregs,
.help_msg = "showPc",
.action_msg = "Show Regs",
+ .enable_mask = SYSRQ_ENABLE_DUMP,
};
.handler = sysrq_handle_showstate,
.help_msg = "showTasks",
.action_msg = "Show State",
+ .enable_mask = SYSRQ_ENABLE_DUMP,
};
.handler = sysrq_handle_showmem,
.help_msg = "showMem",
.action_msg = "Show Memory",
+ .enable_mask = SYSRQ_ENABLE_DUMP,
};
/* SHOW SYSRQ HANDLERS BLOCK */
.handler = sysrq_handle_term,
.help_msg = "tErm",
.action_msg = "Terminate All Tasks",
+ .enable_mask = SYSRQ_ENABLE_SIGNAL,
+};
+
+static void moom_callback(void *ignored)
+{
+ out_of_memory(&NODE_DATA(0)->node_zonelists[ZONE_NORMAL], GFP_KERNEL, 0);
+}
+
+static DECLARE_WORK(moom_work, moom_callback, NULL);
+
+static void sysrq_handle_moom(int key, struct pt_regs *pt_regs,
+ struct tty_struct *tty)
+{
+ schedule_work(&moom_work);
+}
+static struct sysrq_key_op sysrq_moom_op = {
+ .handler = sysrq_handle_moom,
+ .help_msg = "Full",
+ .action_msg = "Manual OOM execution",
};
static void sysrq_handle_kill(int key, struct pt_regs *pt_regs,
.handler = sysrq_handle_kill,
.help_msg = "kIll",
.action_msg = "Kill All Tasks",
+ .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)
+{
+ normalize_rt_tasks();
+}
+static struct sysrq_key_op sysrq_unrt_op = {
+ .handler = sysrq_handle_unrt,
+ .help_msg = "Nice",
+ .action_msg = "Nice All RT Tasks",
+ .enable_mask = SYSRQ_ENABLE_RTNICE,
+};
/* Key Operations table and lock */
-static spinlock_t sysrq_key_table_lock = SPIN_LOCK_UNLOCKED;
+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,
it is handled specially on the sparc
and will never arrive */
/* b */ &sysrq_reboot_op,
-/* c */ NULL,
-/* d */ NULL,
+#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 */ NULL,
+/* f */ &sysrq_moom_op,
/* g */ NULL,
/* h */ NULL,
/* i */ &sysrq_kill_op,
#endif
/* l */ NULL,
/* m */ &sysrq_showmem_op,
-/* n */ NULL,
+/* n */ &sysrq_unrt_op,
/* o */ NULL, /* This will often be registered
as 'Off' at init time */
/* p */ &sysrq_showregs_op,
return retval;
}
-/*
- * table lock and unlocking functions, exposed to modules
- */
-
-void __sysrq_lock_table (void) { spin_lock(&sysrq_key_table_lock); }
-
-void __sysrq_unlock_table (void) { spin_unlock(&sysrq_key_table_lock); }
-
/*
* get and put functions for the table, exposed to modules.
*/
return op_p;
}
-void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) {
+static void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) {
int i;
i = sysrq_key_table_key2index(key);
sysrq_key_table[i] = op_p;
}
-/*
- * 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)
-{
- if (!sysrq_enabled)
- return;
-
- __sysrq_lock_table();
- __handle_sysrq_nolock(key, pt_regs, tty);
- __sysrq_unlock_table();
-}
-
/*
* 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_nolock(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty, int check_mask)
{
struct sysrq_key_op *op_p;
int orig_log_level;
int i, j;
-
- if (!sysrq_enabled)
- return;
+ unsigned long flags;
+ spin_lock_irqsave(&sysrq_key_table_lock, flags);
orig_log_level = console_loglevel;
console_loglevel = 7;
printk(KERN_INFO "SysRq : ");
op_p = __sysrq_get_key_op(key);
if (op_p) {
- printk ("%s\n", op_p->action_msg);
- console_loglevel = orig_log_level;
- op_p->handler(key, pt_regs, tty);
+ /* 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);
+ console_loglevel = orig_log_level;
+ op_p->handler(key, pt_regs, tty);
+ }
+ else
+ printk("This sysrq operation is disabled.\n");
} else {
printk("HELP : ");
/* Only print the help msg once per handler */
printk ("\n");
console_loglevel = orig_log_level;
}
+ spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
+}
+
+/*
+ * 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)
+{
+ if (!sysrq_enabled)
+ return;
+ __handle_sysrq(key, pt_regs, tty, 1);
+}
+
+static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
+ struct sysrq_key_op *remove_op_p) {
+
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sysrq_key_table_lock, flags);
+ if (__sysrq_get_key_op(key) == remove_op_p) {
+ __sysrq_put_key_op(key, insert_op_p);
+ retval = 0;
+ } else {
+ retval = -1;
+ }
+ spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
+
+ return retval;
+}
+
+int register_sysrq_key(int key, struct sysrq_key_op *op_p)
+{
+ return __sysrq_swap_key_ops(key, op_p, NULL);
+}
+
+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(__handle_sysrq_nolock);
-EXPORT_SYMBOL(__sysrq_lock_table);
-EXPORT_SYMBOL(__sysrq_unlock_table);
-EXPORT_SYMBOL(__sysrq_get_key_op);
-EXPORT_SYMBOL(__sysrq_put_key_op);
+EXPORT_SYMBOL(register_sysrq_key);
+EXPORT_SYMBOL(unregister_sysrq_key);