#include <linux/slab.h>
 #include <linux/irqnr.h>
 #include <linux/pci.h>
+#include <linux/spinlock.h>
 
 #ifdef CONFIG_X86
 #include <asm/desc.h>
  */
 static DEFINE_MUTEX(irq_mapping_update_lock);
 
+/*
+ * Lock protecting event handling loop against removing event channels.
+ * Adding of event channels is no issue as the associated IRQ becomes active
+ * only after everything is setup (before request_[threaded_]irq() the handler
+ * can't be entered for an event, as the event channel will be unmasked only
+ * then).
+ */
+static DEFINE_RWLOCK(evtchn_rwlock);
+
+/*
+ * Lock hierarchy:
+ *
+ * irq_mapping_update_lock
+ *   evtchn_rwlock
+ *     IRQ-desc lock
+ */
+
 static LIST_HEAD(xen_irq_list_head);
 
 /* IRQ <-> VIRQ mapping. */
        unsigned col;
 
        for (col = 0; col < EVTCHN_PER_ROW; col++)
-               evtchn_to_irq[row][col] = -1;
+               WRITE_ONCE(evtchn_to_irq[row][col], -1);
 }
 
 static void clear_evtchn_to_irq_all(void)
                clear_evtchn_to_irq_row(row);
        }
 
-       evtchn_to_irq[row][col] = irq;
+       WRITE_ONCE(evtchn_to_irq[row][col], irq);
        return 0;
 }
 
                return -1;
        if (evtchn_to_irq[EVTCHN_ROW(evtchn)] == NULL)
                return -1;
-       return evtchn_to_irq[EVTCHN_ROW(evtchn)][EVTCHN_COL(evtchn)];
+       return READ_ONCE(evtchn_to_irq[EVTCHN_ROW(evtchn)][EVTCHN_COL(evtchn)]);
 }
 
 /* Get info for IRQ */
  */
 unsigned int evtchn_from_irq(unsigned irq)
 {
-       if (unlikely(WARN(irq >= nr_irqs, "Invalid irq %d!\n", irq)))
+       const struct irq_info *info = NULL;
+
+       if (likely(irq < nr_irqs))
+               info = info_for_irq(irq);
+       if (!info)
                return 0;
 
-       return info_for_irq(irq)->evtchn;
+       return info->evtchn;
 }
 
 unsigned irq_from_evtchn(unsigned int evtchn)
 static void xen_free_irq(unsigned irq)
 {
        struct irq_info *info = info_for_irq(irq);
+       unsigned long flags;
 
        if (WARN_ON(!info))
                return;
 
+       write_lock_irqsave(&evtchn_rwlock, flags);
+
        list_del(&info->list);
 
        set_info_for_irq(irq, NULL);
 
        WARN_ON(info->refcnt > 0);
 
+       write_unlock_irqrestore(&evtchn_rwlock, flags);
+
        kfree(info);
 
        /* Legacy IRQ descriptors are managed by the arch. */
        int cpu = get_cpu();
        unsigned count;
 
+       read_lock(&evtchn_rwlock);
+
        do {
                vcpu_info->evtchn_upcall_pending = 0;
 
        } while (count != 1 || vcpu_info->evtchn_upcall_pending);
 
 out:
+       read_unlock(&evtchn_rwlock);
 
        put_cpu();
 }