Add handling for epoll error and disconnect conditions EPOLLERR,
EPOLLHUP and EPOLLRDHUP.

These events indicate that the interrupt file descriptor is in
an error state or there has been a hangup.

Only do this for interrupts that are read in eal. Interrupts that
are read outside eal should deal with disconnect/error events
appropriate to their functionality. e.g. virtio interrupt handling
has reconnect mechanisms for some cases.

Also, treat no bytes read as an error condition.

Bugzilla ID: 1873
Fixes: af75078fece3 ("first public release")
Cc: [email protected]

Signed-off-by: Kevin Traynor <[email protected]>
Acked-by: David Marchand <[email protected]>
---
 lib/eal/linux/eal_interrupts.c | 72 ++++++++++++++++++++++------------
 1 file changed, 46 insertions(+), 26 deletions(-)

diff --git a/lib/eal/linux/eal_interrupts.c b/lib/eal/linux/eal_interrupts.c
index 9db978923a..f3f6bdd01d 100644
--- a/lib/eal/linux/eal_interrupts.c
+++ b/lib/eal/linux/eal_interrupts.c
@@ -887,4 +887,26 @@ rte_intr_disable(const struct rte_intr_handle *intr_handle)
 }
 
+static void
+eal_intr_source_remove_and_free(struct rte_intr_source *src)
+{
+       struct rte_intr_callback *cb, *next;
+
+       /* Remove the interrupt source */
+       rte_spinlock_lock(&intr_lock);
+       TAILQ_REMOVE(&intr_sources, src, next);
+       rte_spinlock_unlock(&intr_lock);
+
+       /* Free callbacks */
+       for (cb = TAILQ_FIRST(&src->callbacks); cb; cb = next) {
+               next = TAILQ_NEXT(cb, next);
+               TAILQ_REMOVE(&src->callbacks, cb, next);
+               free(cb);
+       }
+
+       /* Free the interrupt source */
+       rte_intr_instance_free(src->intr_handle);
+       free(src);
+}
+
 static int
 eal_intr_process_interrupts(struct epoll_event *events, int nfds)
@@ -952,40 +974,38 @@ eal_intr_process_interrupts(struct epoll_event *events, 
int nfds)
 
                if (bytes_read > 0) {
-                       /**
+                       /*
+                        * Check for epoll error or disconnect events for
+                        * interrupts that are read directly in eal.
+                        */
+                       if (events[n].events & (EPOLLERR | EPOLLHUP | 
EPOLLRDHUP)) {
+                               EAL_LOG(ERR, "Disconnect condition on fd %d "
+                                       "(events=0x%x), removing from epoll",
+                                       events[n].data.fd, events[n].events);
+                               eal_intr_source_remove_and_free(src);
+                               return -1;
+                       }
+
+                       /*
                         * read out to clear the ready-to-be-read flag
                         * for epoll_wait.
                         */
                        bytes_read = read(events[n].data.fd, &buf, bytes_read);
-                       if (bytes_read < 0) {
+                       if (bytes_read > 0) {
+                               call = true;
+                       } else if (bytes_read < 0) {
                                if (errno == EINTR || errno == EWOULDBLOCK)
                                        continue;
 
-                               EAL_LOG(ERR, "Error reading from file "
-                                       "descriptor %d: %s",
+                               EAL_LOG(ERR, "Error reading from file 
descriptor %d: %s",
                                        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);
-                               }
-                               rte_intr_instance_free(src->intr_handle);
-                               free(src);
+                       } else {
+                               EAL_LOG(ERR, "Read nothing from file descriptor 
%d",
+                                       events[n].data.fd);
+                       }
+                       if (bytes_read <= 0) {
+                               eal_intr_source_remove_and_free(src);
                                return -1;
-                       } else if (bytes_read == 0)
-                               EAL_LOG(ERR, "Read nothing from file "
-                                       "descriptor %d", events[n].data.fd);
-                       else
-                               call = true;
+                       }
                }
 
-- 
2.53.0

Reply via email to