Commit 4b448974 authored by Jason Baron's avatar Jason Baron Committed by Linus Torvalds

[PATCH] fix alt-sysrq deadlock

The sysrq code is taking a spinlock from both interrupt and process context
in an unsafe and deadlocky manner.

Move all those inlined functions out of sysrq.h, into sysrq.c then withdraw
all those exported-to-modules helper functions then remove
__sysrq_trylock_table() altogether and then use spin_lock_irqsave() in the
appropriate places.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 1eccda34
...@@ -283,14 +283,6 @@ static int sysrq_key_table_key2index(int key) { ...@@ -283,14 +283,6 @@ static int sysrq_key_table_key2index(int key) {
return retval; 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. * get and put functions for the table, exposed to modules.
*/ */
...@@ -323,8 +315,9 @@ void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty) ...@@ -323,8 +315,9 @@ void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
struct sysrq_key_op *op_p; struct sysrq_key_op *op_p;
int orig_log_level; int orig_log_level;
int i, j; int i, j;
unsigned long flags;
__sysrq_lock_table(); spin_lock_irqsave(&sysrq_key_table_lock, flags);
orig_log_level = console_loglevel; orig_log_level = console_loglevel;
console_loglevel = 7; console_loglevel = 7;
printk(KERN_INFO "SysRq : "); printk(KERN_INFO "SysRq : ");
...@@ -346,7 +339,7 @@ void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty) ...@@ -346,7 +339,7 @@ void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
printk ("\n"); printk ("\n");
console_loglevel = orig_log_level; console_loglevel = orig_log_level;
} }
__sysrq_unlock_table(); spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
} }
/* /*
...@@ -361,8 +354,34 @@ void handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty) ...@@ -361,8 +354,34 @@ void handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
__handle_sysrq(key, pt_regs, tty); __handle_sysrq(key, pt_regs, tty);
} }
int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
struct sysrq_key_op *remove_op_p) {
int retval;
unsigned long flags;
spin_lock_irqsave(&sysrq_key_table_lock, flags);
if (__sysrq_get_key_op(key) == remove_op_p) {
__sysrq_put_key_op(key, insert_op_p);
retval = 0;
} else {
retval = -1;
}
spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
return retval;
}
int register_sysrq_key(int key, struct sysrq_key_op *op_p)
{
return __sysrq_swap_key_ops(key, op_p, NULL);
}
int unregister_sysrq_key(int key, struct sysrq_key_op *op_p)
{
return __sysrq_swap_key_ops(key, NULL, op_p);
}
EXPORT_SYMBOL(handle_sysrq); EXPORT_SYMBOL(handle_sysrq);
EXPORT_SYMBOL(__sysrq_lock_table); EXPORT_SYMBOL(register_sysrq_key);
EXPORT_SYMBOL(__sysrq_unlock_table); EXPORT_SYMBOL(unregister_sysrq_key);
EXPORT_SYMBOL(__sysrq_get_key_op);
EXPORT_SYMBOL(__sysrq_put_key_op);
...@@ -31,49 +31,8 @@ struct sysrq_key_op { ...@@ -31,49 +31,8 @@ struct sysrq_key_op {
void handle_sysrq(int, struct pt_regs *, struct tty_struct *); void handle_sysrq(int, struct pt_regs *, struct tty_struct *);
void __handle_sysrq(int, struct pt_regs *, struct tty_struct *); void __handle_sysrq(int, struct pt_regs *, struct tty_struct *);
int register_sysrq_key(int, struct sysrq_key_op *);
/* int unregister_sysrq_key(int, struct sysrq_key_op *);
* Sysrq registration manipulation functions
*/
void __sysrq_lock_table (void);
void __sysrq_unlock_table (void);
struct sysrq_key_op *__sysrq_get_key_op (int key);
void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p);
extern __inline__ int
__sysrq_swap_key_ops_nolock(int key, struct sysrq_key_op *insert_op_p,
struct sysrq_key_op *remove_op_p)
{
int retval;
if (__sysrq_get_key_op(key) == remove_op_p) {
__sysrq_put_key_op(key, insert_op_p);
retval = 0;
} else {
retval = -1;
}
return retval;
}
extern __inline__ int
__sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
struct sysrq_key_op *remove_op_p) {
int retval;
__sysrq_lock_table();
retval = __sysrq_swap_key_ops_nolock(key, insert_op_p, remove_op_p);
__sysrq_unlock_table();
return retval;
}
static inline int register_sysrq_key(int key, struct sysrq_key_op *op_p)
{
return __sysrq_swap_key_ops(key, op_p, NULL);
}
static inline int unregister_sysrq_key(int key, struct sysrq_key_op *op_p)
{
return __sysrq_swap_key_ops(key, NULL, op_p);
}
#else #else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment