diff options
| author | Linus Torvalds <[email protected]> | 2014-12-19 13:26:08 -0800 | 
|---|---|---|
| committer | Linus Torvalds <[email protected]> | 2014-12-19 13:26:08 -0800 | 
| commit | ac88ee3b6cbac80c32556a39fe16c4bbc55fcbc5 (patch) | |
| tree | 5053b061053b244e1ed3fd55bc0736c8dd1e6753 /kernel/irq/proc.c | |
| parent | a54455766b9e3d3c27a6cef758355d2591d81d68 (diff) | |
| parent | c291ee622165cb2c8d4e7af63fffd499354a23be (diff) | |
Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq core fix from Thomas Gleixner:
 "A single fix plugging a long standing race between proc/stat and
  proc/interrupts access and freeing of interrupt descriptors"
* 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  genirq: Prevent proc race against freeing of irq descriptors
Diffstat (limited to 'kernel/irq/proc.c')
| -rw-r--r-- | kernel/irq/proc.c | 22 | 
1 files changed, 21 insertions, 1 deletions
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index ac1ba2f11032..9dc9bfd8a678 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -15,6 +15,23 @@  #include "internals.h" +/* + * Access rules: + * + * procfs protects read/write of /proc/irq/N/ files against a + * concurrent free of the interrupt descriptor. remove_proc_entry() + * immediately prevents new read/writes to happen and waits for + * already running read/write functions to complete. + * + * We remove the proc entries first and then delete the interrupt + * descriptor from the radix tree and free it. So it is guaranteed + * that irq_to_desc(N) is valid as long as the read/writes are + * permitted by procfs. + * + * The read from /proc/interrupts is a different problem because there + * is no protection. So the lookup and the access to irqdesc + * information must be protected by sparse_irq_lock. + */  static struct proc_dir_entry *root_irq_dir;  #ifdef CONFIG_SMP @@ -437,9 +454,10 @@ int show_interrupts(struct seq_file *p, void *v)  		seq_putc(p, '\n');  	} +	irq_lock_sparse();  	desc = irq_to_desc(i);  	if (!desc) -		return 0; +		goto outsparse;  	raw_spin_lock_irqsave(&desc->lock, flags);  	for_each_online_cpu(j) @@ -479,6 +497,8 @@ int show_interrupts(struct seq_file *p, void *v)  	seq_putc(p, '\n');  out:  	raw_spin_unlock_irqrestore(&desc->lock, flags); +outsparse: +	irq_unlock_sparse();  	return 0;  }  #endif  |