sysrq.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:12k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

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