PageRenderTime 44ms CodeModel.GetById 17ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/char/sysrq.c

https://bitbucket.org/evzijst/gittest
C | 432 lines | 332 code | 54 blank | 46 comment | 30 complexity | d93047d7d62d139829aefdb775a052f1 MD5 | raw file
  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/kernel.h>
 30#include <linux/module.h>
 31#include <linux/suspend.h>
 32#include <linux/writeback.h>
 33#include <linux/buffer_head.h>		/* for fsync_bdev() */
 34#include <linux/swap.h>
 35#include <linux/spinlock.h>
 36#include <linux/vt_kern.h>
 37#include <linux/workqueue.h>
 38
 39#include <asm/ptrace.h>
 40
 41/* Whether we react on sysrq keys or just ignore them */
 42int sysrq_enabled = 1;
 43
 44/* Loglevel sysrq handler */
 45static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs,
 46				  struct tty_struct *tty) 
 47{
 48	int i;
 49	i = key - '0';
 50	console_loglevel = 7;
 51	printk("Loglevel set to %d\n", i);
 52	console_loglevel = i;
 53}	
 54static struct sysrq_key_op sysrq_loglevel_op = {
 55	.handler	= sysrq_handle_loglevel,
 56	.help_msg	= "loglevel0-8",
 57	.action_msg	= "Changing Loglevel",
 58	.enable_mask	= SYSRQ_ENABLE_LOG,
 59};
 60
 61
 62/* SAK sysrq handler */
 63#ifdef CONFIG_VT
 64static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs,
 65			     struct tty_struct *tty) 
 66{
 67	if (tty)
 68		do_SAK(tty);
 69	reset_vc(vc_cons[fg_console].d);
 70}
 71static struct sysrq_key_op sysrq_SAK_op = {
 72	.handler	= sysrq_handle_SAK,
 73	.help_msg	= "saK",
 74	.action_msg	= "SAK",
 75	.enable_mask	= SYSRQ_ENABLE_KEYBOARD,
 76};
 77#endif
 78
 79#ifdef CONFIG_VT
 80/* unraw sysrq handler */
 81static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs,
 82			       struct tty_struct *tty) 
 83{
 84	struct kbd_struct *kbd = &kbd_table[fg_console];
 85
 86	if (kbd)
 87		kbd->kbdmode = VC_XLATE;
 88}
 89static struct sysrq_key_op sysrq_unraw_op = {
 90	.handler	= sysrq_handle_unraw,
 91	.help_msg	= "unRaw",
 92	.action_msg	= "Keyboard mode set to XLATE",
 93	.enable_mask	= SYSRQ_ENABLE_KEYBOARD,
 94};
 95#endif /* CONFIG_VT */
 96
 97/* reboot sysrq handler */
 98static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs,
 99				struct tty_struct *tty) 
100{
101	local_irq_enable();
102	machine_restart(NULL);
103}
104
105static struct sysrq_key_op sysrq_reboot_op = {
106	.handler	= sysrq_handle_reboot,
107	.help_msg	= "reBoot",
108	.action_msg	= "Resetting",
109	.enable_mask	= SYSRQ_ENABLE_BOOT,
110};
111
112static void sysrq_handle_sync(int key, struct pt_regs *pt_regs,
113			      struct tty_struct *tty) 
114{
115	emergency_sync();
116}
117
118static struct sysrq_key_op sysrq_sync_op = {
119	.handler	= sysrq_handle_sync,
120	.help_msg	= "Sync",
121	.action_msg	= "Emergency Sync",
122	.enable_mask	= SYSRQ_ENABLE_SYNC,
123};
124
125static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs,
126				 struct tty_struct *tty) 
127{
128	emergency_remount();
129}
130
131static struct sysrq_key_op sysrq_mountro_op = {
132	.handler	= sysrq_handle_mountro,
133	.help_msg	= "Unmount",
134	.action_msg	= "Emergency Remount R/O",
135	.enable_mask	= SYSRQ_ENABLE_REMOUNT,
136};
137
138/* END SYNC SYSRQ HANDLERS BLOCK */
139
140
141/* SHOW SYSRQ HANDLERS BLOCK */
142
143static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs,
144				  struct tty_struct *tty) 
145{
146	if (pt_regs)
147		show_regs(pt_regs);
148}
149static struct sysrq_key_op sysrq_showregs_op = {
150	.handler	= sysrq_handle_showregs,
151	.help_msg	= "showPc",
152	.action_msg	= "Show Regs",
153	.enable_mask	= SYSRQ_ENABLE_DUMP,
154};
155
156
157static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs,
158				   struct tty_struct *tty) 
159{
160	show_state();
161}
162static struct sysrq_key_op sysrq_showstate_op = {
163	.handler	= sysrq_handle_showstate,
164	.help_msg	= "showTasks",
165	.action_msg	= "Show State",
166	.enable_mask	= SYSRQ_ENABLE_DUMP,
167};
168
169
170static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs,
171				 struct tty_struct *tty) 
172{
173	show_mem();
174}
175static struct sysrq_key_op sysrq_showmem_op = {
176	.handler	= sysrq_handle_showmem,
177	.help_msg	= "showMem",
178	.action_msg	= "Show Memory",
179	.enable_mask	= SYSRQ_ENABLE_DUMP,
180};
181
182/* SHOW SYSRQ HANDLERS BLOCK */
183
184
185/* SIGNAL SYSRQ HANDLERS BLOCK */
186
187/* signal sysrq helper function
188 * Sends a signal to all user processes */
189static void send_sig_all(int sig)
190{
191	struct task_struct *p;
192
193	for_each_process(p) {
194		if (p->mm && p->pid != 1)
195			/* Not swapper, init nor kernel thread */
196			force_sig(sig, p);
197	}
198}
199
200static void sysrq_handle_term(int key, struct pt_regs *pt_regs,
201			      struct tty_struct *tty) 
202{
203	send_sig_all(SIGTERM);
204	console_loglevel = 8;
205}
206static struct sysrq_key_op sysrq_term_op = {
207	.handler	= sysrq_handle_term,
208	.help_msg	= "tErm",
209	.action_msg	= "Terminate All Tasks",
210	.enable_mask	= SYSRQ_ENABLE_SIGNAL,
211};
212
213static void moom_callback(void *ignored)
214{
215	out_of_memory(GFP_KERNEL);
216}
217
218static DECLARE_WORK(moom_work, moom_callback, NULL);
219
220static void sysrq_handle_moom(int key, struct pt_regs *pt_regs,
221			      struct tty_struct *tty)
222{
223	schedule_work(&moom_work);
224}
225static struct sysrq_key_op sysrq_moom_op = {
226	.handler	= sysrq_handle_moom,
227	.help_msg	= "Full",
228	.action_msg	= "Manual OOM execution",
229};
230
231static void sysrq_handle_kill(int key, struct pt_regs *pt_regs,
232			      struct tty_struct *tty) 
233{
234	send_sig_all(SIGKILL);
235	console_loglevel = 8;
236}
237static struct sysrq_key_op sysrq_kill_op = {
238	.handler	= sysrq_handle_kill,
239	.help_msg	= "kIll",
240	.action_msg	= "Kill All Tasks",
241	.enable_mask	= SYSRQ_ENABLE_SIGNAL,
242};
243
244/* END SIGNAL SYSRQ HANDLERS BLOCK */
245
246static void sysrq_handle_unrt(int key, struct pt_regs *pt_regs,
247				struct tty_struct *tty)
248{
249	normalize_rt_tasks();
250}
251static struct sysrq_key_op sysrq_unrt_op = {
252	.handler	= sysrq_handle_unrt,
253	.help_msg	= "Nice",
254	.action_msg	= "Nice All RT Tasks",
255	.enable_mask	= SYSRQ_ENABLE_RTNICE,
256};
257
258/* Key Operations table and lock */
259static DEFINE_SPINLOCK(sysrq_key_table_lock);
260#define SYSRQ_KEY_TABLE_LENGTH 36
261static struct sysrq_key_op *sysrq_key_table[SYSRQ_KEY_TABLE_LENGTH] = {
262/* 0 */	&sysrq_loglevel_op,
263/* 1 */	&sysrq_loglevel_op,
264/* 2 */	&sysrq_loglevel_op,
265/* 3 */	&sysrq_loglevel_op,
266/* 4 */	&sysrq_loglevel_op,
267/* 5 */	&sysrq_loglevel_op,
268/* 6 */	&sysrq_loglevel_op,
269/* 7 */	&sysrq_loglevel_op,
270/* 8 */	&sysrq_loglevel_op,
271/* 9 */	&sysrq_loglevel_op,
272/* a */	NULL, /* Don't use for system provided sysrqs,
273		 it is handled specially on the sparc
274		 and will never arrive */
275/* b */	&sysrq_reboot_op,
276/* c */ NULL,
277/* d */	NULL,
278/* e */	&sysrq_term_op,
279/* f */	&sysrq_moom_op,
280/* g */	NULL,
281/* h */	NULL,
282/* i */	&sysrq_kill_op,
283/* j */	NULL,
284#ifdef CONFIG_VT
285/* k */	&sysrq_SAK_op,
286#else
287/* k */	NULL,
288#endif
289/* l */	NULL,
290/* m */	&sysrq_showmem_op,
291/* n */	&sysrq_unrt_op,
292/* o */	NULL, /* This will often be registered
293		 as 'Off' at init time */
294/* p */	&sysrq_showregs_op,
295/* q */	NULL,
296#ifdef CONFIG_VT
297/* r */	&sysrq_unraw_op,
298#else
299/* r */ NULL,
300#endif
301/* s */	&sysrq_sync_op,
302/* t */	&sysrq_showstate_op,
303/* u */	&sysrq_mountro_op,
304/* v */	NULL, /* May be assigned at init time by SMP VOYAGER */
305/* w */	NULL,
306/* x */	NULL,
307/* y */	NULL,
308/* z */	NULL
309};
310
311/* key2index calculation, -1 on invalid index */
312static int sysrq_key_table_key2index(int key) {
313	int retval;
314	if ((key >= '0') && (key <= '9')) {
315		retval = key - '0';
316	} else if ((key >= 'a') && (key <= 'z')) {
317		retval = key + 10 - 'a';
318	} else {
319		retval = -1;
320	}
321	return retval;
322}
323
324/*
325 * get and put functions for the table, exposed to modules.
326 */
327
328struct sysrq_key_op *__sysrq_get_key_op (int key) {
329        struct sysrq_key_op *op_p;
330        int i;
331	
332	i = sysrq_key_table_key2index(key);
333        op_p = (i == -1) ? NULL : sysrq_key_table[i];
334        return op_p;
335}
336
337void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) {
338        int i;
339
340	i = sysrq_key_table_key2index(key);
341        if (i != -1)
342                sysrq_key_table[i] = op_p;
343}
344
345/*
346 * This is the non-locking version of handle_sysrq
347 * It must/can only be called by sysrq key handlers,
348 * as they are inside of the lock
349 */
350
351void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty, int check_mask)
352{
353	struct sysrq_key_op *op_p;
354	int orig_log_level;
355	int i, j;
356	unsigned long flags;
357
358	spin_lock_irqsave(&sysrq_key_table_lock, flags);
359	orig_log_level = console_loglevel;
360	console_loglevel = 7;
361	printk(KERN_INFO "SysRq : ");
362
363        op_p = __sysrq_get_key_op(key);
364        if (op_p) {
365		/* Should we check for enabled operations (/proc/sysrq-trigger should not)
366		 * and is the invoked operation enabled? */
367		if (!check_mask || sysrq_enabled == 1 ||
368		    (sysrq_enabled & op_p->enable_mask)) {
369			printk ("%s\n", op_p->action_msg);
370			console_loglevel = orig_log_level;
371			op_p->handler(key, pt_regs, tty);
372		}
373		else
374			printk("This sysrq operation is disabled.\n");
375	} else {
376		printk("HELP : ");
377		/* Only print the help msg once per handler */
378		for (i=0; i<SYSRQ_KEY_TABLE_LENGTH; i++) 
379		if (sysrq_key_table[i]) {
380			for (j=0; sysrq_key_table[i] != sysrq_key_table[j]; j++);
381			if (j == i)
382				printk ("%s ", sysrq_key_table[i]->help_msg);
383		}
384		printk ("\n");
385		console_loglevel = orig_log_level;
386	}
387	spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
388}
389
390/*
391 * This function is called by the keyboard handler when SysRq is pressed
392 * and any other keycode arrives.
393 */
394
395void handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
396{
397	if (!sysrq_enabled)
398		return;
399	__handle_sysrq(key, pt_regs, tty, 1);
400}
401
402int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
403                                struct sysrq_key_op *remove_op_p) {
404
405	int retval;
406	unsigned long flags;
407
408	spin_lock_irqsave(&sysrq_key_table_lock, flags);
409	if (__sysrq_get_key_op(key) == remove_op_p) {
410		__sysrq_put_key_op(key, insert_op_p);
411		retval = 0;
412	} else {
413		retval = -1;
414	}
415	spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
416
417	return retval;
418}
419
420int register_sysrq_key(int key, struct sysrq_key_op *op_p)
421{
422	return __sysrq_swap_key_ops(key, op_p, NULL);
423}
424
425int unregister_sysrq_key(int key, struct sysrq_key_op *op_p)
426{
427	return __sysrq_swap_key_ops(key, NULL, op_p);
428}
429
430EXPORT_SYMBOL(handle_sysrq);
431EXPORT_SYMBOL(register_sysrq_key);
432EXPORT_SYMBOL(unregister_sysrq_key);