|
@@ -510,9 +510,8 @@ void __handle_sysrq(int key, bool check_mask)
|
|
|
struct sysrq_key_op *op_p;
|
|
|
int orig_log_level;
|
|
|
int i;
|
|
|
- unsigned long flags;
|
|
|
|
|
|
- spin_lock_irqsave(&sysrq_key_table_lock, flags);
|
|
|
+ rcu_read_lock();
|
|
|
/*
|
|
|
* Raise the apparent loglevel to maximum so that the sysrq header
|
|
|
* is shown to provide the user with positive feedback. We do not
|
|
@@ -554,7 +553,7 @@ void __handle_sysrq(int key, bool check_mask)
|
|
|
printk("\n");
|
|
|
console_loglevel = orig_log_level;
|
|
|
}
|
|
|
- spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
|
|
|
+ rcu_read_unlock();
|
|
|
}
|
|
|
|
|
|
void handle_sysrq(int key)
|
|
@@ -1043,16 +1042,23 @@ static 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);
|
|
|
+ spin_lock(&sysrq_key_table_lock);
|
|
|
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);
|
|
|
+ spin_unlock(&sysrq_key_table_lock);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * A concurrent __handle_sysrq either got the old op or the new op.
|
|
|
+ * Wait for it to go away before returning, so the code for an old
|
|
|
+ * op is not freed (eg. on module unload) while it is in use.
|
|
|
+ */
|
|
|
+ synchronize_rcu();
|
|
|
+
|
|
|
return retval;
|
|
|
}
|
|
|
|