linux-old/drivers/char/sysrq.c
<<
>>
Prefs
   1/* -*- linux-c -*-
   2 *
   3 *      $Id: sysrq.c,v 1.15 1998/08/23 14:56:41 mj Exp $
   4 *
   5 *      Linux Magic System Request Key Hacks
   6 *
   7 *      (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
   8 *      based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>
   9 *
  10 *      (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
  11 *      overhauled to use key registration
  12 *      based upon discusions in irc://irc.openprojects.net/#kernelnewbies
  13 */
  14
  15#include <linux/config.h>
  16#include <linux/sched.h>
  17#include <linux/interrupt.h>
  18#include <linux/mm.h>
  19#include <linux/fs.h>
  20#include <linux/tty.h>
  21#include <linux/mount.h>
  22#include <linux/kdev_t.h>
  23#include <linux/major.h>
  24#include <linux/reboot.h>
  25#include <linux/sysrq.h>
  26#include <linux/kbd_kern.h>
  27#include <linux/quotaops.h>
  28#include <linux/smp_lock.h>
  29#include <linux/module.h>
  30
  31#include <linux/spinlock.h>
  32
  33#include <asm/ptrace.h>
  34
  35extern void reset_vc(unsigned int);
  36extern struct list_head super_blocks;
  37
  38/* Whether we react on sysrq keys or just ignore them */
  39int sysrq_enabled = 1;
  40
  41/* Machine specific power off function */
  42void (*sysrq_power_off)(void);
  43
  44/* Loglevel sysrq handler */
  45static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs,
  46                struct kbd_struct *kbd, struct tty_struct *tty) {
  47        int i;
  48        i = key - '0';
  49        console_loglevel = 7;
  50        printk("Loglevel set to %d\n", i);
  51        console_loglevel = i;
  52}       
  53static struct sysrq_key_op sysrq_loglevel_op = {
  54        handler:        sysrq_handle_loglevel,
  55        help_msg:       "loglevel0-8",
  56        action_msg:     "Changing Loglevel",
  57};
  58
  59
  60/* SAK sysrq handler */
  61#ifdef CONFIG_VT
  62static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs,
  63                struct kbd_struct *kbd, struct tty_struct *tty) {
  64        if (tty)
  65                do_SAK(tty);
  66        reset_vc(fg_console);
  67}
  68static struct sysrq_key_op sysrq_SAK_op = {
  69        handler:        sysrq_handle_SAK,
  70        help_msg:       "saK",
  71        action_msg:     "SAK",
  72};
  73#endif
  74
  75
  76/* unraw sysrq handler */
  77static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs,
  78                struct kbd_struct *kbd, struct tty_struct *tty) {
  79        if (kbd)
  80                kbd->kbdmode = VC_XLATE;
  81}
  82static struct sysrq_key_op sysrq_unraw_op = {
  83        handler:        sysrq_handle_unraw,
  84        help_msg:       "unRaw",
  85        action_msg:     "Keyboard mode set to XLATE",
  86};
  87
  88
  89/* reboot sysrq handler */
  90static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs,
  91                struct kbd_struct *kbd, struct tty_struct *tty) {
  92        machine_restart(NULL);
  93}
  94static struct sysrq_key_op sysrq_reboot_op = {
  95        handler:        sysrq_handle_reboot,
  96        help_msg:       "reBoot",
  97        action_msg:     "Resetting",
  98};
  99
 100
 101
 102/* SYNC SYSRQ HANDLERS BLOCK */
 103
 104/* do_emergency_sync helper function */
 105/* Guesses if the device is a local hard drive */
 106static int is_local_disk(kdev_t dev) {
 107        unsigned int major;
 108        major = MAJOR(dev);
 109
 110        switch (major) {
 111        case IDE0_MAJOR:
 112        case IDE1_MAJOR:
 113        case IDE2_MAJOR:
 114        case IDE3_MAJOR:
 115        case IDE4_MAJOR:
 116        case IDE5_MAJOR:
 117        case IDE6_MAJOR:
 118        case IDE7_MAJOR:
 119        case IDE8_MAJOR:
 120        case IDE9_MAJOR:
 121        case SCSI_DISK0_MAJOR:
 122        case SCSI_DISK1_MAJOR:
 123        case SCSI_DISK2_MAJOR:
 124        case SCSI_DISK3_MAJOR:
 125        case SCSI_DISK4_MAJOR:
 126        case SCSI_DISK5_MAJOR:
 127        case SCSI_DISK6_MAJOR:
 128        case SCSI_DISK7_MAJOR:
 129        case XT_DISK_MAJOR:
 130                return 1;
 131        default:
 132                return 0;
 133        }
 134}
 135
 136/* do_emergency_sync helper function */
 137static void go_sync(struct super_block *sb, int remount_flag)
 138{
 139        int orig_loglevel;
 140        orig_loglevel = console_loglevel;
 141        console_loglevel = 7;
 142        printk(KERN_INFO "%sing device %s ... ",
 143               remount_flag ? "Remount" : "Sync",
 144               kdevname(sb->s_dev));
 145
 146        if (remount_flag) { /* Remount R/O */
 147                int ret, flags;
 148                struct list_head *p;
 149
 150                if (sb->s_flags & MS_RDONLY) {
 151                        printk("R/O\n");
 152                        return;
 153                }
 154
 155                file_list_lock();
 156                for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
 157                        struct file *file = list_entry(p, struct file, f_list);
 158                        if (file->f_dentry && file_count(file)
 159                                && S_ISREG(file->f_dentry->d_inode->i_mode))
 160                                file->f_mode &= ~2;
 161                }
 162                file_list_unlock();
 163                DQUOT_OFF(sb);
 164                fsync_dev(sb->s_dev);
 165                flags = MS_RDONLY;
 166                if (sb->s_op && sb->s_op->remount_fs) {
 167                        ret = sb->s_op->remount_fs(sb, &flags, NULL);
 168                        if (ret)
 169                                printk("error %d\n", ret);
 170                        else {
 171                                sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
 172                                printk("OK\n");
 173                        }
 174                } else
 175                        printk("nothing to do\n");
 176        } else { /* Sync only */
 177                fsync_dev(sb->s_dev);
 178                printk("OK\n");
 179        }
 180        console_loglevel = orig_loglevel;
 181}
 182/*
 183 * Emergency Sync or Unmount. We cannot do it directly, so we set a special
 184 * flag and wake up the bdflush kernel thread which immediately calls this function.
 185 * We process all mounted hard drives first to recover from crashed experimental
 186 * block devices and malfunctional network filesystems.
 187 */
 188
 189volatile int emergency_sync_scheduled;
 190
 191void do_emergency_sync(void) {
 192        struct super_block *sb;
 193        int remount_flag;
 194        int orig_loglevel;
 195
 196        lock_kernel();
 197        remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT);
 198        emergency_sync_scheduled = 0;
 199
 200        for (sb = sb_entry(super_blocks.next);
 201             sb != sb_entry(&super_blocks); 
 202             sb = sb_entry(sb->s_list.next))
 203                if (is_local_disk(sb->s_dev))
 204                        go_sync(sb, remount_flag);
 205
 206        for (sb = sb_entry(super_blocks.next);
 207             sb != sb_entry(&super_blocks); 
 208             sb = sb_entry(sb->s_list.next))
 209                if (!is_local_disk(sb->s_dev) && MAJOR(sb->s_dev))
 210                        go_sync(sb, remount_flag);
 211
 212        unlock_kernel();
 213
 214        orig_loglevel = console_loglevel;
 215        console_loglevel = 7;
 216        printk(KERN_INFO "Done.\n");
 217        console_loglevel = orig_loglevel;
 218}
 219
 220static void sysrq_handle_sync(int key, struct pt_regs *pt_regs,
 221                struct kbd_struct *kbd, struct tty_struct *tty) {
 222        emergency_sync_scheduled = EMERG_SYNC;
 223        wakeup_bdflush();
 224}
 225static struct sysrq_key_op sysrq_sync_op = {
 226        handler:        sysrq_handle_sync,
 227        help_msg:       "Sync",
 228        action_msg:     "Emergency Sync",
 229};
 230
 231static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs,
 232                struct kbd_struct *kbd, struct tty_struct *tty) {
 233        emergency_sync_scheduled = EMERG_REMOUNT;
 234        wakeup_bdflush();
 235}
 236static struct sysrq_key_op sysrq_mountro_op = {
 237        handler:        sysrq_handle_mountro,
 238        help_msg:       "Unmount",
 239        action_msg:     "Emergency Remount R/O",
 240};
 241
 242/* END SYNC SYSRQ HANDLERS BLOCK */
 243
 244
 245/* SHOW SYSRQ HANDLERS BLOCK */
 246
 247static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs,
 248                struct kbd_struct *kbd, struct tty_struct *tty) {
 249        if (pt_regs)
 250                show_regs(pt_regs);
 251}
 252static struct sysrq_key_op sysrq_showregs_op = {
 253        handler:        sysrq_handle_showregs,
 254        help_msg:       "showPc",
 255        action_msg:     "Show Regs",
 256};
 257
 258
 259static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs,
 260                struct kbd_struct *kbd, struct tty_struct *tty) {
 261        show_state();
 262}
 263static struct sysrq_key_op sysrq_showstate_op = {
 264        handler:        sysrq_handle_showstate,
 265        help_msg:       "showTasks",
 266        action_msg:     "Show State",
 267};
 268
 269
 270static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs,
 271                struct kbd_struct *kbd, struct tty_struct *tty) {
 272        show_mem();
 273}
 274static struct sysrq_key_op sysrq_showmem_op = {
 275        handler:        sysrq_handle_showmem,
 276        help_msg:       "showMem",
 277        action_msg:     "Show Memory",
 278};
 279
 280/* SHOW SYSRQ HANDLERS BLOCK */
 281
 282
 283/* SIGNAL SYSRQ HANDLERS BLOCK */
 284
 285/* signal sysrq helper function
 286 * Sends a signal to all user processes */
 287static void send_sig_all(int sig)
 288{
 289        struct task_struct *p;
 290
 291        for_each_task(p) {
 292                if (p->mm && p->pid != 1)
 293                        /* Not swapper, init nor kernel thread */
 294                        force_sig(sig, p);
 295        }
 296}
 297
 298static void sysrq_handle_term(int key, struct pt_regs *pt_regs,
 299                struct kbd_struct *kbd, struct tty_struct *tty) {
 300        send_sig_all(SIGTERM);
 301        console_loglevel = 8;
 302}
 303static struct sysrq_key_op sysrq_term_op = {
 304        handler:        sysrq_handle_term,
 305        help_msg:       "tErm",
 306        action_msg:     "Terminate All Tasks",
 307};
 308
 309static void sysrq_handle_kill(int key, struct pt_regs *pt_regs,
 310                struct kbd_struct *kbd, struct tty_struct *tty) {
 311        send_sig_all(SIGKILL);
 312        console_loglevel = 8;
 313}
 314static struct sysrq_key_op sysrq_kill_op = {
 315        handler:        sysrq_handle_kill,
 316        help_msg:       "kIll",
 317        action_msg:     "Kill All Tasks",
 318};
 319
 320/* END SIGNAL SYSRQ HANDLERS BLOCK */
 321
 322
 323/* Key Operations table and lock */
 324static spinlock_t sysrq_key_table_lock = SPIN_LOCK_UNLOCKED;
 325#define SYSRQ_KEY_TABLE_LENGTH 36
 326static struct sysrq_key_op *sysrq_key_table[SYSRQ_KEY_TABLE_LENGTH] = {
 327/* 0 */ &sysrq_loglevel_op,
 328/* 1 */ &sysrq_loglevel_op,
 329/* 2 */ &sysrq_loglevel_op,
 330/* 3 */ &sysrq_loglevel_op,
 331/* 4 */ &sysrq_loglevel_op,
 332/* 5 */ &sysrq_loglevel_op,
 333/* 6 */ &sysrq_loglevel_op,
 334/* 7 */ &sysrq_loglevel_op,
 335/* 8 */ &sysrq_loglevel_op,
 336/* 9 */ &sysrq_loglevel_op,
 337/* a */ NULL, /* Don't use for system provided sysrqs,
 338                 it is handled specially on the spark
 339                 and will never arive */
 340/* b */ &sysrq_reboot_op,
 341/* c */ NULL,
 342/* d */ NULL,
 343/* e */ &sysrq_term_op,
 344/* f */ NULL,
 345/* g */ NULL,
 346/* h */ NULL,
 347/* i */ &sysrq_kill_op,
 348/* j */ NULL,
 349#ifdef CONFIG_VT
 350/* k */ &sysrq_SAK_op,
 351#else
 352/* k */ NULL,
 353#endif
 354/* l */ NULL,
 355/* m */ &sysrq_showmem_op,
 356/* n */ NULL,
 357/* o */ NULL, /* This will often be registered
 358                 as 'Off' at init time */
 359/* p */ &sysrq_showregs_op,
 360/* q */ NULL,
 361/* r */ &sysrq_unraw_op,
 362/* s */ &sysrq_sync_op,
 363/* t */ &sysrq_showstate_op,
 364/* u */ &sysrq_mountro_op,
 365/* v */ NULL,
 366/* w */ NULL,
 367/* x */ NULL,
 368/* y */ NULL,
 369/* z */ NULL
 370};
 371
 372/* key2index calculation, -1 on invalid index */
 373static __inline__ int sysrq_key_table_key2index(int key) {
 374        int retval;
 375        if ((key >= '0') && (key <= '9')) {
 376                retval = key - '0';
 377        } else if ((key >= 'a') && (key <= 'z')) {
 378                retval = key + 10 - 'a';
 379        } else {
 380                retval = -1;
 381        }
 382        return retval;
 383}
 384
 385/*
 386 * table lock and unlocking functions, exposed to modules
 387 */
 388
 389void __sysrq_lock_table (void) { spin_lock(&sysrq_key_table_lock); }
 390
 391void __sysrq_unlock_table (void) { spin_unlock(&sysrq_key_table_lock); }
 392
 393/*
 394 * get and put functions for the table, exposed to modules.
 395 */
 396
 397struct sysrq_key_op *__sysrq_get_key_op (int key) {
 398        struct sysrq_key_op *op_p;
 399        int i;
 400        
 401        i = sysrq_key_table_key2index(key);
 402        op_p = (i == -1) ? NULL : sysrq_key_table[i];
 403        return op_p;
 404}
 405
 406void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) {
 407        int i;
 408
 409        i = sysrq_key_table_key2index(key);
 410        if (i != -1)
 411                sysrq_key_table[i] = op_p;
 412}
 413
 414/*
 415 * This function is called by the keyboard handler when SysRq is pressed
 416 * and any other keycode arrives.
 417 */
 418
 419void handle_sysrq(int key, struct pt_regs *pt_regs,
 420                  struct kbd_struct *kbd, struct tty_struct *tty) {
 421        if (!sysrq_enabled)
 422                return;
 423
 424        __sysrq_lock_table();
 425        __handle_sysrq_nolock(key, pt_regs, kbd, tty);
 426        __sysrq_unlock_table();
 427}
 428
 429/*
 430 * This is the non-locking version of handle_sysrq
 431 * It must/can only be called by sysrq key handlers,
 432 * as they are inside of the lock
 433 */
 434
 435void __handle_sysrq_nolock(int key, struct pt_regs *pt_regs,
 436                  struct kbd_struct *kbd, struct tty_struct *tty) {
 437        struct sysrq_key_op *op_p;
 438        int orig_log_level;
 439        int i, j;
 440        
 441        if (!sysrq_enabled)
 442                return;
 443
 444        orig_log_level = console_loglevel;
 445        console_loglevel = 7;
 446        printk(KERN_INFO "SysRq : ");
 447
 448        op_p = __sysrq_get_key_op(key);
 449        if (op_p) {
 450                printk ("%s\n", op_p->action_msg);
 451                console_loglevel = orig_log_level;
 452                op_p->handler(key, pt_regs, kbd, tty);
 453        } else {
 454                printk("HELP : ");
 455                /* Only print the help msg once per handler */
 456                for (i=0; i<SYSRQ_KEY_TABLE_LENGTH; i++) 
 457                if (sysrq_key_table[i]) {
 458                        for (j=0; sysrq_key_table[i] != sysrq_key_table[j]; j++);
 459                        if (j == i)
 460                                printk ("%s ", sysrq_key_table[i]->help_msg);
 461                }
 462                printk ("\n");
 463                console_loglevel = orig_log_level;
 464        }
 465}
 466
 467EXPORT_SYMBOL(handle_sysrq);
 468EXPORT_SYMBOL(__handle_sysrq_nolock);
 469EXPORT_SYMBOL(__sysrq_lock_table);
 470EXPORT_SYMBOL(__sysrq_unlock_table);
 471EXPORT_SYMBOL(__sysrq_get_key_op);
 472EXPORT_SYMBOL(__sysrq_put_key_op);
 473
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.