diff options
Diffstat (limited to 'drivers/tty/sysrq.c')
-rw-r--r-- | drivers/tty/sysrq.c | 18 |
1 files changed, 12 insertions, 6 deletions
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index b767a64e49d9..7430e87d7352 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -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; } |