summaryrefslogtreecommitdiffstats
path: root/0001-xen-events-avoid-removing-an-event-channel-while-han.patch
diff options
context:
space:
mode:
Diffstat (limited to '0001-xen-events-avoid-removing-an-event-channel-while-han.patch')
-rw-r--r--0001-xen-events-avoid-removing-an-event-channel-while-han.patch161
1 files changed, 0 insertions, 161 deletions
diff --git a/0001-xen-events-avoid-removing-an-event-channel-while-han.patch b/0001-xen-events-avoid-removing-an-event-channel-while-han.patch
deleted file mode 100644
index cd4ac3df3..000000000
--- a/0001-xen-events-avoid-removing-an-event-channel-while-han.patch
+++ /dev/null
@@ -1,161 +0,0 @@
-From 073d0552ead5bfc7a3a9c01de590e924f11b5dd2 Mon Sep 17 00:00:00 2001
-From: Juergen Gross <jgross@suse.com>
-Date: Mon, 7 Sep 2020 15:47:27 +0200
-Subject: [PATCH] xen/events: avoid removing an event channel while handling it
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Today it can happen that an event channel is being removed from the
-system while the event handling loop is active. This can lead to a
-race resulting in crashes or WARN() splats when trying to access the
-irq_info structure related to the event channel.
-
-Fix this problem by using a rwlock taken as reader in the event
-handling loop and as writer when deallocating the irq_info structure.
-
-As the observed problem was a NULL dereference in evtchn_from_irq()
-make this function more robust against races by testing the irq_info
-pointer to be not NULL before dereferencing it.
-
-And finally make all accesses to evtchn_to_irq[row][col] atomic ones
-in order to avoid seeing partial updates of an array element in irq
-handling. Note that irq handling can be entered only for event channels
-which have been valid before, so any not populated row isn't a problem
-in this regard, as rows are only ever added and never removed.
-
-This is XSA-331.
-
-Cc: stable@vger.kernel.org
-Reported-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
-Reported-by: Jinoh Kang <luke1337@theori.io>
-Signed-off-by: Juergen Gross <jgross@suse.com>
-Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
-Reviewed-by: Wei Liu <wl@xen.org>
----
- drivers/xen/events/events_base.c | 41 ++++++++++++++++++++++++++++----
- 1 file changed, 36 insertions(+), 5 deletions(-)
-
-diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
-index 6f02c18fa65c..407741ece084 100644
---- a/drivers/xen/events/events_base.c
-+++ b/drivers/xen/events/events_base.c
-@@ -33,6 +33,7 @@
- #include <linux/slab.h>
- #include <linux/irqnr.h>
- #include <linux/pci.h>
-+#include <linux/spinlock.h>
-
- #ifdef CONFIG_X86
- #include <asm/desc.h>
-@@ -71,6 +72,23 @@ const struct evtchn_ops *evtchn_ops;
- */
- 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. */
-@@ -105,7 +123,7 @@ static void clear_evtchn_to_irq_row(unsigned row)
- 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)
-@@ -142,7 +160,7 @@ static int set_evtchn_to_irq(evtchn_port_t evtchn, unsigned int irq)
- clear_evtchn_to_irq_row(row);
- }
-
-- evtchn_to_irq[row][col] = irq;
-+ WRITE_ONCE(evtchn_to_irq[row][col], irq);
- return 0;
- }
-
-@@ -152,7 +170,7 @@ int get_evtchn_to_irq(evtchn_port_t evtchn)
- 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 */
-@@ -261,10 +279,14 @@ static void xen_irq_info_cleanup(struct irq_info *info)
- */
- evtchn_port_t evtchn_from_irq(unsigned irq)
- {
-- if (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 int irq_from_evtchn(evtchn_port_t evtchn)
-@@ -440,16 +462,21 @@ static int __must_check xen_allocate_irq_gsi(unsigned gsi)
- 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. */
-@@ -1233,6 +1260,8 @@ static void __xen_evtchn_do_upcall(void)
- struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
- int cpu = smp_processor_id();
-
-+ read_lock(&evtchn_rwlock);
-+
- do {
- vcpu_info->evtchn_upcall_pending = 0;
-
-@@ -1243,6 +1272,8 @@ static void __xen_evtchn_do_upcall(void)
- virt_rmb(); /* Hypervisor can set upcall pending. */
-
- } while (vcpu_info->evtchn_upcall_pending);
-+
-+ read_unlock(&evtchn_rwlock);
- }
-
- void xen_evtchn_do_upcall(struct pt_regs *regs)
---
-2.28.0
-