patch-2.4.10 linux/drivers/char/sysrq.c
Next file: linux/drivers/char/toshiba.c
Previous file: linux/drivers/char/synclink.c
Back to the patch index
Back to the overall index
- Lines: 550
- Date:
Thu Sep 20 14:12:28 2001
- Orig file:
v2.4.9/linux/drivers/char/sysrq.c
- Orig date:
Sun Aug 12 13:27:59 2001
diff -u --recursive --new-file v2.4.9/linux/drivers/char/sysrq.c linux/drivers/char/sysrq.c
@@ -6,6 +6,10 @@
*
* (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
* based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>
+ *
+ * (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
+ * overhauled to use key registration
+ * based upon discusions in irc://irc.openprojects.net/#kernelnewbies
*/
#include <linux/config.h>
@@ -24,6 +28,8 @@
#include <linux/smp_lock.h>
#include <linux/module.h>
+#include <linux/spinlock.h>
+
#include <asm/ptrace.h>
extern void reset_vc(unsigned int);
@@ -35,136 +41,83 @@
/* Machine specific power off function */
void (*sysrq_power_off)(void);
-EXPORT_SYMBOL(sysrq_power_off);
-
-/* Send a signal to all user processes */
+/* Loglevel sysrq handler */
+static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs,
+ struct kbd_struct *kbd, struct tty_struct *tty) {
+ int i;
+ i = key - '0';
+ console_loglevel = 7;
+ printk("%d\n", i);
+ console_loglevel = i;
+}
+static struct sysrq_key_op sysrq_loglevel_op = {
+ handler: sysrq_handle_loglevel,
+ help_msg: "loglevel0-8",
+ action_msg: "Loglevel set to ",
+};
-static void send_sig_all(int sig, int even_init)
-{
- struct task_struct *p;
- for_each_task(p) {
- if (p->mm) { /* Not swapper nor kernel thread */
- if (p->pid == 1 && even_init) /* Ugly hack to kill init */
- p->pid = 0x8000;
- force_sig(sig, p);
- }
- }
+/* SAK sysrq handler */
+#ifdef CONFIG_VT
+static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs,
+ struct kbd_struct *kbd, struct tty_struct *tty) {
+ if (tty)
+ do_SAK(tty);
+ reset_vc(fg_console);
}
+static struct sysrq_key_op sysrq_SAK_op = {
+ handler: sysrq_handle_SAK,
+ help_msg: "saK",
+ action_msg: "SAK\n",
+};
+#endif
-/*
- * 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 kbd_struct *kbd, struct tty_struct *tty)
-{
- int orig_log_level = console_loglevel;
+/* unraw sysrq handler */
+static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs,
+ struct kbd_struct *kbd, struct tty_struct *tty) {
+ if (kbd)
+ kbd->kbdmode = VC_XLATE;
+}
+static struct sysrq_key_op sysrq_unraw_op = {
+ handler: sysrq_handle_unraw,
+ help_msg: "unRaw",
+ action_msg: "Keyboard mode set to XLATE\n",
+};
- if (!sysrq_enabled)
- return;
- if (!key)
- return;
+/* reboot sysrq handler */
+static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs,
+ struct kbd_struct *kbd, struct tty_struct *tty) {
+ machine_restart(NULL);
+}
+static struct sysrq_key_op sysrq_reboot_op = {
+ handler: sysrq_handle_reboot,
+ help_msg: "reBoot",
+ action_msg: "Resetting\n",
+};
- console_loglevel = 7;
- printk(KERN_INFO "SysRq: ");
- switch (key) {
- case 'r': /* R -- Reset raw mode */
- if (kbd) {
- kbd->kbdmode = VC_XLATE;
- printk("Keyboard mode set to XLATE\n");
- }
- break;
-#ifdef CONFIG_VT
- case 'k': /* K -- SAK */
- printk("SAK\n");
- if (tty)
- do_SAK(tty);
- reset_vc(fg_console);
- break;
-#endif
- case 'b': /* B -- boot immediately */
- printk("Resetting\n");
- machine_restart(NULL);
- break;
- case 'o': /* O -- power off */
- if (sysrq_power_off) {
- printk("Power off\n");
- sysrq_power_off();
- }
- break;
- case 's': /* S -- emergency sync */
- printk("Emergency Sync\n");
- emergency_sync_scheduled = EMERG_SYNC;
- wakeup_bdflush();
- break;
- case 'u': /* U -- emergency remount R/O */
- printk("Emergency Remount R/O\n");
- emergency_sync_scheduled = EMERG_REMOUNT;
- wakeup_bdflush();
- break;
- case 'p': /* P -- show PC */
- printk("Show Regs\n");
- if (pt_regs)
- show_regs(pt_regs);
- break;
- case 't': /* T -- show task info */
- printk("Show State\n");
- show_state();
- break;
- case 'm': /* M -- show memory info */
- printk("Show Memory\n");
- show_mem();
- break;
- case '0' ... '9': /* 0-9 -- set console logging level */
- orig_log_level = key - '0';
- printk("Log level set to %d\n", orig_log_level);
- break;
- case 'e': /* E -- terminate all user processes */
- printk("Terminate All Tasks\n");
- send_sig_all(SIGTERM, 0);
- orig_log_level = 8; /* We probably have killed syslogd */
- break;
- case 'i': /* I -- kill all user processes */
- printk("Kill All Tasks\n");
- send_sig_all(SIGKILL, 0);
- orig_log_level = 8;
- break;
- case 'l': /* L -- kill all processes including init */
- printk("Kill ALL Tasks (even init)\n");
- send_sig_all(SIGKILL, 1);
- orig_log_level = 8;
- break;
- default: /* Unknown: help */
- if (kbd)
- printk("unRaw ");
-#ifdef CONFIG_VT
- if (tty)
- printk("saK ");
-#endif
- printk("Boot ");
- if (sysrq_power_off)
- printk("Off ");
- printk("Sync Unmount showPc showTasks showMem loglevel0-8 tErm kIll killalL\n");
- /* Don't use 'A' as it's handled specially on the Sparc */
- }
- console_loglevel = orig_log_level;
-}
-/* Aux routines for the syncer */
+/* SYNC SYSRQ HANDLERS BLOCK */
-static int is_local_disk(kdev_t dev) /* Guess if the device is a local hard drive */
-{
- unsigned int major = MAJOR(dev);
+/* do_emergency_sync helper function */
+/* Guesses if the device is a local hard drive */
+static int is_local_disk(kdev_t dev) {
+ unsigned int major;
+ major = MAJOR(dev);
switch (major) {
case IDE0_MAJOR:
case IDE1_MAJOR:
case IDE2_MAJOR:
case IDE3_MAJOR:
+ case IDE4_MAJOR:
+ case IDE5_MAJOR:
+ case IDE6_MAJOR:
+ case IDE7_MAJOR:
+ case IDE8_MAJOR:
+ case IDE9_MAJOR:
case SCSI_DISK0_MAJOR:
case SCSI_DISK1_MAJOR:
case SCSI_DISK2_MAJOR:
@@ -173,19 +126,24 @@
case SCSI_DISK5_MAJOR:
case SCSI_DISK6_MAJOR:
case SCSI_DISK7_MAJOR:
+ case XT_DISK_MAJOR:
return 1;
default:
return 0;
}
}
+/* do_emergency_sync helper function */
static void go_sync(struct super_block *sb, int remount_flag)
{
+ int orig_loglevel;
+ orig_loglevel = console_loglevel;
+ console_loglevel = 7;
printk(KERN_INFO "%sing device %s ... ",
remount_flag ? "Remount" : "Sync",
kdevname(sb->s_dev));
- if (remount_flag) { /* Remount R/O */
+ if (remount_flag) { /* Remount R/O */
int ret, flags;
struct list_head *p;
@@ -215,12 +173,12 @@
}
} else
printk("nothing to do\n");
- } else {
- fsync_dev(sb->s_dev); /* Sync only */
+ } else { /* Sync only */
+ fsync_dev(sb->s_dev);
printk("OK\n");
}
+ console_loglevel = orig_loglevel;
}
-
/*
* Emergency Sync or Unmount. We cannot do it directly, so we set a special
* flag and wake up the bdflush kernel thread which immediately calls this function.
@@ -230,10 +188,10 @@
int emergency_sync_scheduled;
-void do_emergency_sync(void)
-{
+void do_emergency_sync(void) {
struct super_block *sb;
int remount_flag;
+ int orig_loglevel;
lock_kernel();
remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT);
@@ -252,5 +210,277 @@
go_sync(sb, remount_flag);
unlock_kernel();
+
+ orig_loglevel = console_loglevel;
+ console_loglevel = 7;
printk(KERN_INFO "Done.\n");
+ console_loglevel = orig_loglevel;
+}
+
+static void sysrq_handle_sync(int key, struct pt_regs *pt_regs,
+ struct kbd_struct *kbd, struct tty_struct *tty) {
+ emergency_sync_scheduled = EMERG_SYNC;
+ wakeup_bdflush();
+}
+static struct sysrq_key_op sysrq_sync_op = {
+ handler: sysrq_handle_sync,
+ help_msg: "Sync",
+ action_msg: "Emergency Sync\n",
+};
+
+static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs,
+ struct kbd_struct *kbd, struct tty_struct *tty) {
+ emergency_sync_scheduled = EMERG_REMOUNT;
+ wakeup_bdflush();
+}
+static struct sysrq_key_op sysrq_mountro_op = {
+ handler: sysrq_handle_mountro,
+ help_msg: "Unmount",
+ action_msg: "Emergency Remount R/0\n",
+};
+
+/* END SYNC SYSRQ HANDLERS BLOCK */
+
+
+/* SHOW SYSRQ HANDLERS BLOCK */
+
+static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs,
+ struct kbd_struct *kbd, struct tty_struct *tty) {
+ if (pt_regs)
+ show_regs(pt_regs);
+}
+static struct sysrq_key_op sysrq_showregs_op = {
+ handler: sysrq_handle_showregs,
+ help_msg: "showPc",
+ action_msg: "Show Regs\n",
+};
+
+
+static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs,
+ struct kbd_struct *kbd, struct tty_struct *tty) {
+ show_state();
+}
+static struct sysrq_key_op sysrq_showstate_op = {
+ handler: sysrq_handle_showstate,
+ help_msg: "showTasks",
+ action_msg: "Show State\n",
+};
+
+
+static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs,
+ struct kbd_struct *kbd, struct tty_struct *tty) {
+ show_mem();
+}
+static struct sysrq_key_op sysrq_showmem_op = {
+ handler: sysrq_handle_showmem,
+ help_msg: "showMem",
+ action_msg: "Show Memory\n",
+};
+
+/* SHOW SYSRQ HANDLERS BLOCK */
+
+
+/* SIGNAL SYSRQ HANDLERS BLOCK */
+
+/* signal sysrq helper function
+ * Sends a signal to all user processes */
+static void send_sig_all(int sig, int even_init)
+{
+ struct task_struct *p;
+
+ for_each_task(p) {
+ if (p->mm) { /* Not swapper nor kernel thread */
+ if (p->pid == 1 && even_init)
+ /* Ugly hack to kill init */
+ p->pid = 0x8000;
+ if (p->pid != 1)
+ force_sig(sig, p);
+ }
+ }
+}
+
+static void sysrq_handle_term(int key, struct pt_regs *pt_regs,
+ struct kbd_struct *kbd, struct tty_struct *tty) {
+ send_sig_all(SIGTERM, 0);
+ console_loglevel = 8;
+}
+static struct sysrq_key_op sysrq_term_op = {
+ handler: sysrq_handle_term,
+ help_msg: "tErm",
+ action_msg: "Terminate All Tasks\n",
+};
+
+static void sysrq_handle_kill(int key, struct pt_regs *pt_regs,
+ struct kbd_struct *kbd, struct tty_struct *tty) {
+ send_sig_all(SIGKILL, 0);
+ console_loglevel = 8;
+}
+static struct sysrq_key_op sysrq_kill_op = {
+ handler: sysrq_handle_kill,
+ help_msg: "kIll",
+ action_msg: "Kill All Tasks\n",
+};
+
+static void sysrq_handle_killall(int key, struct pt_regs *pt_regs,
+ struct kbd_struct *kbd, struct tty_struct *tty) {
+ send_sig_all(SIGKILL, 1);
+ console_loglevel = 8;
+}
+static struct sysrq_key_op sysrq_killall_op = {
+ handler: sysrq_handle_killall,
+ help_msg: "killalL",
+ action_msg: "Kill All Tasks (even init)\n",
+};
+
+/* END SIGNAL SYSRQ HANDLERS BLOCK */
+
+
+/* Key Operations table and lock */
+spinlock_t sysrq_key_table_lock = SPIN_LOCK_UNLOCKED;
+#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 spark
+ and will never arive */
+/* b */ &sysrq_reboot_op,
+/* c */ NULL,
+/* d */ NULL,
+/* e */ &sysrq_term_op,
+/* f */ NULL,
+/* g */ NULL,
+/* h */ NULL,
+/* i */ &sysrq_kill_op,
+/* j */ NULL,
+#ifdef CONFIG_VT
+/* k */ &sysrq_SAK_op,
+#else
+/* k */ NULL,
+#endif
+/* l */ &sysrq_killall_op,
+/* m */ &sysrq_showmem_op,
+/* n */ NULL,
+/* o */ NULL, /* This will often be registered
+ as 'Off' at init time */
+/* p */ &sysrq_showregs_op,
+/* q */ NULL,
+/* r */ &sysrq_unraw_op,
+/* s */ &sysrq_sync_op,
+/* t */ &sysrq_showstate_op,
+/* u */ &sysrq_mountro_op,
+/* v */ NULL,
+/* w */ NULL,
+/* x */ NULL,
+/* w */ NULL,
+/* z */ NULL
+};
+
+/* key2index calculation, -1 on invalid index */
+static __inline__ int sysrq_key_table_key2index(int key) {
+ int retval;
+ if ((key >= '0') & (key <= '9')) {
+ retval = key - '0';
+ } else if ((key >= 'a') & (key <= 'z')) {
+ retval = key + 10 - 'a';
+ } else {
+ retval = -1;
+ }
+ 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.
+ */
+
+struct sysrq_key_op *__sysrq_get_key_op (int key) {
+ struct sysrq_key_op *op_p;
+ int i;
+
+ i = sysrq_key_table_key2index(key);
+ op_p = (i == -1) ? NULL : sysrq_key_table[i];
+ return op_p;
}
+
+void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) {
+ int i;
+
+ i = sysrq_key_table_key2index(key);
+ if (i != -1)
+ 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 kbd_struct *kbd, struct tty_struct *tty) {
+ if (!sysrq_enabled)
+ return;
+
+ __sysrq_lock_table();
+ __handle_sysrq_nolock(key, pt_regs, kbd, 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 kbd_struct *kbd, struct tty_struct *tty) {
+ struct sysrq_key_op *op_p;
+ int orig_log_level;
+ int i, j;
+
+ if (!sysrq_enabled)
+ return;
+
+ orig_log_level = console_loglevel;
+ console_loglevel = 7;
+ printk(KERN_INFO "SysRq : ");
+
+ op_p = __sysrq_get_key_op(key);
+ if (op_p) {
+ printk ("%s", op_p->action_msg);
+ op_p->handler(key, pt_regs, kbd, tty);
+ } else {
+ printk("HELP : ");
+ /* Only print the help msg once per handler */
+ for (i=0; i<SYSRQ_KEY_TABLE_LENGTH; i++)
+ if (sysrq_key_table[i]) {
+ for (j=0; sysrq_key_table[i] != sysrq_key_table[j]; j++);
+ if (j == i)
+ printk ("%s ", sysrq_key_table[i]->help_msg);
+ }
+ printk ("\n");
+ }
+ console_loglevel = orig_log_level;
+}
+
+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);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)