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
                printk("\n");
                console_loglevel = orig_log_level;
        }
-       spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
+       rcu_read_unlock();
 }
 
 void handle_sysrq(int key)
                                 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;
 }