Sysrq enhancement: process kill facility

From: S. Parker (linux@sparker.net)
Date: Fri Feb 08 2002 - 12:30:13 EST


Hi,

Here's something that myself and others at Cobalt Networks have found useful.
It extends sysrq to support a way to manually kill a process. In debugging
situations, we have found times where the system gets wedged, and we'ld like
to avoid a reboot. Show tasks provides the pid information.

You enter <alt>-<sysrq>-n ("nuke"), and then prompts for the pid. It supports
backspace and control-U. On serial ports, it retains the same semantics:
a break activates this as a sysrq sequence, but if more than 5-seconds pass
without any input, it drops out of processing input as a sysrq.

Feedback welcome, please cc: me directly.

Cheers,

         ~sparker

diff -ur generic-2.4.17/drivers/char/keyboard.c
sysrq-generic-2.4.17/drivers/char/keyboard.c
--- generic-2.4.17/drivers/char/keyboard.c Tue Sep 18 13:39:51 2001
+++ sysrq-generic-2.4.17/drivers/char/keyboard.c Thu Feb 7 17:59:18
2002
@@ -252,7 +252,7 @@
                 goto out;
         } else if (sysrq_pressed) {
                 if (!up_flag) {
- handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs,
kbd, tty);
+ (void) handle_sysrq(kbd_sysrq_xlate[keycode],
kbd_pt_regs, kbd, tty);
                         goto out;
                 }
         }
Only in sysrq-generic-2.4.17/drivers/char: keyboard.c.orig
diff -ur generic-2.4.17/drivers/char/serial.c
sysrq-generic-2.4.17/drivers/char/serial.c
--- generic-2.4.17/drivers/char/serial.c Fri Dec 21 09:41:54 2001
+++ sysrq-generic-2.4.17/drivers/char/serial.c Thu Feb 7 17:59:18 2002
@@ -645,8 +645,12 @@
                 if (break_pressed && info->line == sercons.index) {
                         if (ch != 0 &&
                             time_before(jiffies, break_pressed + HZ*5)) {
- handle_sysrq(ch, regs, NULL, NULL);
- break_pressed = 0;
+ if (!handle_sysrq(ch, regs, NULL, NULL)) {
+ break_pressed = 0;
+ } else {
+ /* reset time-out! more data needed */
+ break_pressed = jiffies;
+ }
                                 goto ignore_char;
                         }
                         break_pressed = 0;
Only in sysrq-generic-2.4.17/drivers/char: serial.c.orig
diff -ur generic-2.4.17/drivers/char/serial_amba.c
sysrq-generic-2.4.17/drivers/char/serial_amba.c
--- generic-2.4.17/drivers/char/serial_amba.c Sun Sep 16 21:23:14 2001
+++ sysrq-generic-2.4.17/drivers/char/serial_amba.c Thu Feb 7 17:59:18
2002
@@ -356,8 +356,11 @@
  #ifdef SUPPORT_SYSRQ
                 if (info->sysrq) {
                         if (ch && time_before(jiffies, info->sysrq)) {
- handle_sysrq(ch, regs, NULL, NULL);
- info->sysrq = 0;
+ if (!handle_sysrq(ch, regs, NULL, NULL)) {
+ info->sysrq = 0;
+ } else {
+ info->sysrq = jiffies;
+ }
                                 goto ignore_char;
                         }
                         info->sysrq = 0;
diff -ur generic-2.4.17/drivers/char/sysrq.c
sysrq-generic-2.4.17/drivers/char/sysrq.c
--- generic-2.4.17/drivers/char/sysrq.c Fri Dec 21 09:41:54 2001
+++ sysrq-generic-2.4.17/drivers/char/sysrq.c Thu Feb 7 17:59:18 2002
@@ -42,13 +42,14 @@
  void (*sysrq_power_off)(void);

  /* Loglevel sysrq handler */
-static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs,
+static int 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("Loglevel set to %d\n", i);
         console_loglevel = i;
+ return 0;
  }
  static struct sysrq_key_op sysrq_loglevel_op = {
         handler: sysrq_handle_loglevel,
@@ -59,11 +60,12 @@

  /* SAK sysrq handler */
  #ifdef CONFIG_VT
-static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs,
+static int 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);
+ return 0;
  }
  static struct sysrq_key_op sysrq_SAK_op = {
         handler: sysrq_handle_SAK,
@@ -74,10 +76,11 @@

  /* unraw sysrq handler */
-static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs,
+static int sysrq_handle_unraw(int key, struct pt_regs *pt_regs,
                 struct kbd_struct *kbd, struct tty_struct *tty) {
         if (kbd)
                 kbd->kbdmode = VC_XLATE;
+ return 0;
  }
  static struct sysrq_key_op sysrq_unraw_op = {
         handler: sysrq_handle_unraw,
@@ -87,9 +90,10 @@

  /* reboot sysrq handler */
-static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs,
+static int sysrq_handle_reboot(int key, struct pt_regs *pt_regs,
                 struct kbd_struct *kbd, struct tty_struct *tty) {
         machine_restart(NULL);
+ return 0;
  }
  static struct sysrq_key_op sysrq_reboot_op = {
         handler: sysrq_handle_reboot,
@@ -217,10 +221,11 @@
         console_loglevel = orig_loglevel;
  }

-static void sysrq_handle_sync(int key, struct pt_regs *pt_regs,
+static int 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();
+ return 0;
  }
  static struct sysrq_key_op sysrq_sync_op = {
         handler: sysrq_handle_sync,
@@ -228,10 +233,11 @@
         action_msg: "Emergency Sync",
  };

-static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs,
+static int 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();
+ return 0;
  }
  static struct sysrq_key_op sysrq_mountro_op = {
         handler: sysrq_handle_mountro,
@@ -244,10 +250,11 @@

  /* SHOW SYSRQ HANDLERS BLOCK */

-static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs,
+static int 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);
+ return 0;
  }
  static struct sysrq_key_op sysrq_showregs_op = {
         handler: sysrq_handle_showregs,
@@ -256,9 +263,10 @@
  };

-static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs,
+static int sysrq_handle_showstate(int key, struct pt_regs *pt_regs,
                 struct kbd_struct *kbd, struct tty_struct *tty) {
         show_state();
+ return 0;
  }
  static struct sysrq_key_op sysrq_showstate_op = {
         handler: sysrq_handle_showstate,
@@ -267,9 +275,10 @@
  };

-static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs,
+static int sysrq_handle_showmem(int key, struct pt_regs *pt_regs,
                 struct kbd_struct *kbd, struct tty_struct *tty) {
         show_mem();
+ return 0;
  }
  static struct sysrq_key_op sysrq_showmem_op = {
         handler: sysrq_handle_showmem,
@@ -277,6 +286,73 @@
         action_msg: "Show Memory",
  };

+void
+ask_to_kill(buf)
+{
+ char *p;
+ pid_t pid;
+ int errors;
+
+ for (p = buf; *p; p++) {
+ if (*p < '0' || *p > '9') {
+ printk("Bad pid: %s\n", buf);
+ return;
+ }
+ }
+ /* Okay, got a numeric string... */
+ for (p = buf, pid =0; *p; p++) {
+ pid *= 10;
+ pid += *p - '0';
+ }
+ errors = kill_proc(pid, SIGKILL, 1);
+ printk("kill: %d - returns %d\n", pid, errors);
+}
+int in_accumulate;
+char buf[128];
+
+static int
+accumulate_buf(char c)
+{
+ static int i = 0;
+
+ if (c == '\n' || c == '\r') {
+ buf[i] = '\0';
+ printk("\n");
+ ask_to_kill(buf);
+ in_accumulate = 0;
+ i = 0;
+ return 0;
+ }
+ if (c == '\b' || c == '\0177') { /* backspace or delete? */
+ if (i > 0) {
+ i--;
+ printk("\b \b");
+ }
+ return 1;
+ }
+ if (c == '\025') { /* ^U? kill the whole entry */
+ i = 0;
+ printk("XXX\nenter pid to kill: ");
+ return 1;
+ }
+ buf[i++] = c;
+ printk("%c", c);
+ return 1;
+}
+
+
+static int sysrq_handle_nuke(int key, struct pt_regs *pt_regs,
+ struct kbd_struct *kbd, struct tty_struct *tty) {
+ printk("enter pid to kill: ");
+ in_accumulate = 1;
+ return 1;
+}
+static struct sysrq_key_op sysrq_nuke_op = {
+ handler: sysrq_handle_nuke,
+ help_msg: "Nuke",
+ action_msg: "Nuke process",
+};
+
  /* SHOW SYSRQ HANDLERS BLOCK */

@@ -299,10 +375,11 @@
         }
  }

-static void sysrq_handle_term(int key, struct pt_regs *pt_regs,
+static int 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;
+ return 0;
  }
  static struct sysrq_key_op sysrq_term_op = {
         handler: sysrq_handle_term,
@@ -310,10 +387,11 @@
         action_msg: "Terminate All Tasks",
  };

-static void sysrq_handle_kill(int key, struct pt_regs *pt_regs,
+static int 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;
+ return 0;
  }
  static struct sysrq_key_op sysrq_kill_op = {
         handler: sysrq_handle_kill,
@@ -321,10 +399,11 @@
         action_msg: "Kill All Tasks",
  };

-static void sysrq_handle_killall(int key, struct pt_regs *pt_regs,
+static int 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;
+ return 0;
  }
  static struct sysrq_key_op sysrq_killall_op = {
         handler: sysrq_handle_killall,
@@ -368,7 +447,7 @@
  #endif
  /* l */ &sysrq_killall_op,
  /* m */ &sysrq_showmem_op,
-/* n */ NULL,
+/* n */ &sysrq_nuke_op,
  /* o */ NULL, /* This will often be registered
                  as 'Off' at init time */
  /* p */ &sysrq_showregs_op,
@@ -431,14 +510,18 @@
   * and any other keycode arrives.
   */

-void handle_sysrq(int key, struct pt_regs *pt_regs,
- struct kbd_struct *kbd, struct tty_struct *tty) {
+int handle_sysrq(int key, struct pt_regs *pt_regs,
+ struct kbd_struct *kbd, struct tty_struct *tty)
+{
+ int ret_val;
+
         if (!sysrq_enabled)
- return;
+ return 0;

         __sysrq_lock_table();
- __handle_sysrq_nolock(key, pt_regs, kbd, tty);
+ ret_val = __handle_sysrq_nolock(key, pt_regs, kbd, tty);
         __sysrq_unlock_table();
+ return ret_val;
  }

  /*
@@ -447,14 +530,20 @@
   * as they are inside of the lock
   */

-void __handle_sysrq_nolock(int key, struct pt_regs *pt_regs,
+int __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;
+ int ret_val;

         if (!sysrq_enabled)
- return;
+ return 0;
+
+ if (in_accumulate) {
+ ret_val = accumulate_buf(key);
+ return ret_val;
+ }

         orig_log_level = console_loglevel;
         console_loglevel = 7;
@@ -464,7 +553,7 @@
          if (op_p) {
                 printk ("%s\n", op_p->action_msg);
                 console_loglevel = orig_log_level;
- op_p->handler(key, pt_regs, kbd, tty);
+ ret_val = op_p->handler(key, pt_regs, kbd, tty);
         } else {
                 printk("HELP : ");
                 /* Only print the help msg once per handler */
@@ -476,7 +565,9 @@
                 }
                 printk ("\n");
                 console_loglevel = orig_log_level;
+ ret_val = 0;
         }
+ return ret_val;
  }

  EXPORT_SYMBOL(handle_sysrq);
diff -ur generic-2.4.17/drivers/s390/char/ctrlchar.c
sysrq-generic-2.4.17/drivers/s390/char/ctrlchar.c
--- generic-2.4.17/drivers/s390/char/ctrlchar.c Sun Sep 30 12:26:07 2001
+++ sysrq-generic-2.4.17/drivers/s390/char/ctrlchar.c Thu Feb 7 17:59:18
2002
@@ -26,7 +26,7 @@

  static void
  ctrlchar_handle_sysrq(struct tty_struct *tty) {
- handle_sysrq(ctrlchar_sysrq_key, NULL, NULL, tty);
+ (void) handle_sysrq(ctrlchar_sysrq_key, NULL, NULL, tty);
  }
  #endif

diff -ur generic-2.4.17/drivers/tc/zs.c sysrq-generic-2.4.17/drivers/tc/zs.c
--- generic-2.4.17/drivers/tc/zs.c Mon Aug 27 08:56:31 2001
+++ sysrq-generic-2.4.17/drivers/tc/zs.c Thu Feb 7 17:59:18 2002
@@ -444,8 +444,12 @@
                 if (break_pressed && info->line == sercons.index) {
                         if (ch != 0 &&
                             time_before(jiffies, break_pressed + HZ*5)) {
- handle_sysrq(ch, regs, NULL, NULL);
- break_pressed = 0;
+ if (!handle_sysrq(ch, regs, NULL, NULL)) {
+ break_pressed = 0;
+ } else {
+ /* reset time-out! more data needed */
+ break_pressed = jiffies;
+ }
                                 goto ignore_char;
                         }
                         break_pressed = 0;
diff -ur generic-2.4.17/include/linux/sysrq.h
sysrq-generic-2.4.17/include/linux/sysrq.h
--- generic-2.4.17/include/linux/sysrq.h Wed Jan 30 16:47:01 2002
+++ sysrq-generic-2.4.17/include/linux/sysrq.h Thu Feb 7 17:59:18 2002
@@ -18,7 +18,7 @@
  struct tty_struct;

  struct sysrq_key_op {
- void (*handler)(int, struct pt_regs *,
+ int (*handler)(int, struct pt_regs *,
                         struct kbd_struct *, struct tty_struct *);
         char *help_msg;
         char *action_msg;
@@ -29,9 +29,14 @@
  /* Generic SysRq interface -- you may call it from any device driver,
supplying
   * ASCII code of the key, pointer to registers and kbd/tty structs (if they
   * are available -- else NULL's).
+ *
+ * Most sysrq's are single character commands, but to allow for multiple
+ * key-stroke input, handle_sysrq() returns true if the current command
+ * is collecting more input. This matters to serial-based consoles which
+ * base the interpretation of the character on the proximity of the break.
   */

-void handle_sysrq(int, struct pt_regs *,
+int handle_sysrq(int, struct pt_regs *,
                 struct kbd_struct *, struct tty_struct *);

@@ -40,7 +45,7 @@
   * call sysrq handlers
   */

-void __handle_sysrq_nolock(int, struct pt_regs *,
+int __handle_sysrq_nolock(int, struct pt_regs *,
                  struct kbd_struct *, struct tty_struct *);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Fri Feb 15 2002 - 21:00:19 EST