diff options
Diffstat (limited to 'drivers/tty/sysrq.c')
| -rw-r--r-- | drivers/tty/sysrq.c | 31 | 
1 files changed, 20 insertions, 11 deletions
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 40a9fe9d3b1..454b65898e2 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -46,12 +46,13 @@  #include <linux/jiffies.h>  #include <linux/syscalls.h>  #include <linux/of.h> +#include <linux/rcupdate.h>  #include <asm/ptrace.h>  #include <asm/irq_regs.h>  /* Whether we react on sysrq keys or just ignore them */ -static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE; +static int __read_mostly sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE;  static bool __read_mostly sysrq_always_enabled;  unsigned short platform_sysrq_reset_seq[] __weak = { KEY_RESERVED }; @@ -88,7 +89,7 @@ static void sysrq_handle_loglevel(int key)  	int i;  	i = key - '0'; -	console_loglevel = 7; +	console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;  	printk("Loglevel set to %d\n", i);  	console_loglevel = i;  } @@ -343,7 +344,7 @@ static void send_sig_all(int sig)  static void sysrq_handle_term(int key)  {  	send_sig_all(SIGTERM); -	console_loglevel = 8; +	console_loglevel = CONSOLE_LOGLEVEL_DEBUG;  }  static struct sysrq_key_op sysrq_term_op = {  	.handler	= sysrq_handle_term, @@ -387,7 +388,7 @@ static struct sysrq_key_op sysrq_thaw_op = {  static void sysrq_handle_kill(int key)  {  	send_sig_all(SIGKILL); -	console_loglevel = 8; +	console_loglevel = CONSOLE_LOGLEVEL_DEBUG;  }  static struct sysrq_key_op sysrq_kill_op = {  	.handler	= sysrq_handle_kill, @@ -510,9 +511,9 @@ 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_sysrq_start(); +	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 @@ -520,7 +521,7 @@ void __handle_sysrq(int key, bool check_mask)  	 * routing in the consumers of /proc/kmsg.  	 */  	orig_log_level = console_loglevel; -	console_loglevel = 7; +	console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;  	printk(KERN_INFO "SysRq : ");          op_p = __sysrq_get_key_op(key); @@ -554,7 +555,8 @@ 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(); +	rcu_sysrq_end();  }  void handle_sysrq(int key) @@ -1043,16 +1045,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;  }  | 
