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: 0a45657a67 ("pci: rework interrupt handling")
Cc: stable@dpdk.org

Signed-off-by: Brian Russell <brussell@brocade.com>
Signed-off-by: Luca Boccassi <bluca@debian.org>
This commit is contained in:
Luca Boccassi 2018-10-31 18:39:45 +00:00 committed by Thomas Monjalon
parent 6c99085d97
commit 349ac52bbc

View File

@ -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);