--- /dev/null
+From c291ee622165cb2c8d4e7af63fffd499354a23be Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Thu, 11 Dec 2014 23:01:41 +0100
+Subject: genirq: Prevent proc race against freeing of irq descriptors
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+commit c291ee622165cb2c8d4e7af63fffd499354a23be upstream.
+
+Since the rework of the sparse interrupt code to actually free the
+unused interrupt descriptors there exists a race between the /proc
+interfaces to the irq subsystem and the code which frees the interrupt
+descriptor.
+
+CPU0 CPU1
+ show_interrupts()
+ desc = irq_to_desc(X);
+free_desc(desc)
+ remove_from_radix_tree();
+ kfree(desc);
+ raw_spinlock_irq(&desc->lock);
+
+/proc/interrupts is the only interface which can actively corrupt
+kernel memory via the lock access. /proc/stat can only read from freed
+memory. Extremly hard to trigger, but possible.
+
+The interfaces in /proc/irq/N/ are not affected by this because the
+removal of the proc file is serialized in procfs against concurrent
+readers/writers. The removal happens before the descriptor is freed.
+
+For architectures which have CONFIG_SPARSE_IRQ=n this is a non issue
+as the descriptor is never freed. It's merely cleared out with the irq
+descriptor lock held. So any concurrent proc access will either see
+the old correct value or the cleared out ones.
+
+Protect the lookup and access to the irq descriptor in
+show_interrupts() with the sparse_irq_lock.
+
+Provide kstat_irqs_usr() which is protecting the lookup and access
+with sparse_irq_lock and switch /proc/stat to use it.
+
+Document the existing kstat_irqs interfaces so it's clear that the
+caller needs to take care about protection. The users of these
+interfaces are either not affected due to SPARSE_IRQ=n or already
+protected against removal.
+
+Fixes: 1f5a5b87f78f "genirq: Implement a sane sparse_irq allocator"
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/proc/stat.c | 2 -
+ include/linux/kernel_stat.h | 1
+ kernel/irq/internals.h | 8 ++++++
+ kernel/irq/irqdesc.c | 52 ++++++++++++++++++++++++++++++++++++++++++++
+ kernel/irq/proc.c | 22 +++++++++++++++++-
+ 5 files changed, 83 insertions(+), 2 deletions(-)
+
+--- a/fs/proc/stat.c
++++ b/fs/proc/stat.c
+@@ -159,7 +159,7 @@ static int show_stat(struct seq_file *p,
+
+ /* sum again ? it could be updated? */
+ for_each_irq_nr(j)
+- seq_put_decimal_ull(p, ' ', kstat_irqs(j));
++ seq_put_decimal_ull(p, ' ', kstat_irqs_usr(j));
+
+ seq_printf(p,
+ "\nctxt %llu\n"
+--- a/include/linux/kernel_stat.h
++++ b/include/linux/kernel_stat.h
+@@ -74,6 +74,7 @@ static inline unsigned int kstat_softirq
+ * Number of interrupts per specific IRQ source, since bootup
+ */
+ extern unsigned int kstat_irqs(unsigned int irq);
++extern unsigned int kstat_irqs_usr(unsigned int irq);
+
+ /*
+ * Number of interrupts per cpu, since bootup
+--- a/kernel/irq/internals.h
++++ b/kernel/irq/internals.h
+@@ -74,6 +74,14 @@ extern void irq_percpu_disable(struct ir
+ extern void mask_irq(struct irq_desc *desc);
+ extern void unmask_irq(struct irq_desc *desc);
+
++#ifdef CONFIG_SPARSE_IRQ
++extern void irq_lock_sparse(void);
++extern void irq_unlock_sparse(void);
++#else
++static inline void irq_lock_sparse(void) { }
++static inline void irq_unlock_sparse(void) { }
++#endif
++
+ extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
+
+ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action);
+--- a/kernel/irq/irqdesc.c
++++ b/kernel/irq/irqdesc.c
+@@ -131,6 +131,16 @@ static void free_masks(struct irq_desc *
+ static inline void free_masks(struct irq_desc *desc) { }
+ #endif
+
++void irq_lock_sparse(void)
++{
++ mutex_lock(&sparse_irq_lock);
++}
++
++void irq_unlock_sparse(void)
++{
++ mutex_unlock(&sparse_irq_lock);
++}
++
+ static struct irq_desc *alloc_desc(int irq, int node, struct module *owner)
+ {
+ struct irq_desc *desc;
+@@ -167,6 +177,12 @@ static void free_desc(unsigned int irq)
+
+ unregister_irq_proc(irq, desc);
+
++ /*
++ * sparse_irq_lock protects also show_interrupts() and
++ * kstat_irq_usr(). Once we deleted the descriptor from the
++ * sparse tree we can free it. Access in proc will fail to
++ * lookup the descriptor.
++ */
+ mutex_lock(&sparse_irq_lock);
+ delete_irq_desc(irq);
+ mutex_unlock(&sparse_irq_lock);
+@@ -489,6 +505,15 @@ void dynamic_irq_cleanup(unsigned int ir
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
+ }
+
++/**
++ * kstat_irqs_cpu - Get the statistics for an interrupt on a cpu
++ * @irq: The interrupt number
++ * @cpu: The cpu number
++ *
++ * Returns the sum of interrupt counts on @cpu since boot for
++ * @irq. The caller must ensure that the interrupt is not removed
++ * concurrently.
++ */
+ unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
+ {
+ struct irq_desc *desc = irq_to_desc(irq);
+@@ -497,6 +522,14 @@ unsigned int kstat_irqs_cpu(unsigned int
+ *per_cpu_ptr(desc->kstat_irqs, cpu) : 0;
+ }
+
++/**
++ * kstat_irqs - Get the statistics for an interrupt
++ * @irq: The interrupt number
++ *
++ * Returns the sum of interrupt counts on all cpus since boot for
++ * @irq. The caller must ensure that the interrupt is not removed
++ * concurrently.
++ */
+ unsigned int kstat_irqs(unsigned int irq)
+ {
+ struct irq_desc *desc = irq_to_desc(irq);
+@@ -509,3 +542,22 @@ unsigned int kstat_irqs(unsigned int irq
+ sum += *per_cpu_ptr(desc->kstat_irqs, cpu);
+ return sum;
+ }
++
++/**
++ * kstat_irqs_usr - Get the statistics for an interrupt
++ * @irq: The interrupt number
++ *
++ * Returns the sum of interrupt counts on all cpus since boot for
++ * @irq. Contrary to kstat_irqs() this can be called from any
++ * preemptible context. It's protected against concurrent removal of
++ * an interrupt descriptor when sparse irqs are enabled.
++ */
++unsigned int kstat_irqs_usr(unsigned int irq)
++{
++ int sum;
++
++ irq_lock_sparse();
++ sum = kstat_irqs(irq);
++ irq_unlock_sparse();
++ return sum;
++}
+--- 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,
+ 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,
+ seq_putc(p, '\n');
+ out:
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
++outsparse:
++ irq_unlock_sparse();
+ return 0;
+ }
+ #endif