summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorLuca Boccassi <bluca@debian.org>2018-10-31 18:39:45 +0000
committerThomas Monjalon <thomas@monjalon.net>2018-11-02 10:50:49 +0100
commit349ac52bbc5264d774c7e28c62c4e3941055b9c4 (patch)
treeb08c1a9808c8e3c91f38097cc782166eebe537e4 /lib
parent6c99085d972b5f0fddf9f986ea8907ed5dafd086 (diff)
downloaddpdk-349ac52bbc5264d774c7e28c62c4e3941055b9c4.zip
dpdk-349ac52bbc5264d774c7e28c62c4e3941055b9c4.tar.gz
dpdk-349ac52bbc5264d774c7e28c62c4e3941055b9c4.tar.xz
eal/linux: handle UIO read failure in interrupt handler
If a device is unplugged while an interrupt is pending, the read call to the uio device to remove it from the poll wait list can fail resulting in it being continually polled forever. This change checks for the read failing and if so, unregisters the device as an interrupt source and causes the wait list to be rebuilt. This race has been reported and observed in production. Fixes: 0a45657a6794 ("pci: rework interrupt handling") Cc: stable@dpdk.org Signed-off-by: Brian Russell <brussell@brocade.com> Signed-off-by: Luca Boccassi <bluca@debian.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/librte_eal/linuxapp/eal/eal_interrupts.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
index 39252a8..cbac451 100644
--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
@@ -700,7 +700,7 @@ eal_intr_process_interrupts(struct epoll_event *events, int nfds)
bool call = false;
int n, bytes_read;
struct rte_intr_source *src;
- struct rte_intr_callback *cb;
+ struct rte_intr_callback *cb, *next;
union rte_intr_read_buffer buf;
struct rte_intr_callback active_cb;
@@ -780,6 +780,23 @@ eal_intr_process_interrupts(struct epoll_event *events, int nfds)
"descriptor %d: %s\n",
events[n].data.fd,
strerror(errno));
+ /*
+ * The device is unplugged or buggy, remove
+ * it as an interrupt source and return to
+ * force the wait list to be rebuilt.
+ */
+ rte_spinlock_lock(&intr_lock);
+ TAILQ_REMOVE(&intr_sources, src, next);
+ rte_spinlock_unlock(&intr_lock);
+
+ for (cb = TAILQ_FIRST(&src->callbacks); cb;
+ cb = next) {
+ next = TAILQ_NEXT(cb, next);
+ TAILQ_REMOVE(&src->callbacks, cb, next);
+ free(cb);
+ }
+ free(src);
+ return -1;
} else if (bytes_read == 0)
RTE_LOG(ERR, EAL, "Read nothing from file "
"descriptor %d\n", events[n].data.fd);