Daniel P. Berrange 21a02c
commit 9130396214975ba2251082f943c9717281039050
Daniel P. Berrange 21a02c
Author: Daniel P. Berrange <berrange@redhat.com>
Daniel P. Berrange 21a02c
Date:   Thu Jan 12 17:03:03 2012 +0000
Daniel P. Berrange 21a02c
Daniel P. Berrange 21a02c
    Re-write LXC controller end-of-file I/O handling yet again
Daniel P. Berrange 21a02c
    
Daniel P. Berrange 21a02c
    Currently the LXC controller attempts to deal with EOF on a
Daniel P. Berrange 21a02c
    tty by spawning a thread to do an edge triggered epoll_wait().
Daniel P. Berrange 21a02c
    This avoids the normal event loop spinning on POLLHUP. There
Daniel P. Berrange 21a02c
    is a subtle mistake though - even after seeing POLLHUP on a
Daniel P. Berrange 21a02c
    master PTY, it is still perfectly possible & valid to write
Daniel P. Berrange 21a02c
    data to the PTY. There is a buffer that can be filled with
Daniel P. Berrange 21a02c
    data, even when no client is present.
Daniel P. Berrange 21a02c
    
Daniel P. Berrange 21a02c
    The second mistake is that the epoll_wait() thread was not
Daniel P. Berrange 21a02c
    looking for the EPOLLOUT condition, so when a new client
Daniel P. Berrange 21a02c
    connects to the LXC console, it had to explicitly send a
Daniel P. Berrange 21a02c
    character before any queued output would appear.
Daniel P. Berrange 21a02c
    
Daniel P. Berrange 21a02c
    Finally, there was in fact no need to spawn a new thread to
Daniel P. Berrange 21a02c
    deal with epoll_wait(). The epoll file descriptor itself
Daniel P. Berrange 21a02c
    can be poll()'d on normally.
Daniel P. Berrange 21a02c
    
Daniel P. Berrange 21a02c
    This patch attempts to deal with all these problems.
Daniel P. Berrange 21a02c
    
Daniel P. Berrange 21a02c
     - The blocking epoll_wait() thread is replaced by a poll
Daniel P. Berrange 21a02c
       on the epoll file descriptor which then does a non-blocking
Daniel P. Berrange 21a02c
       epoll_wait() to handle events
Daniel P. Berrange 21a02c
     - Even if POLLHUP is seen, we continue trying to write
Daniel P. Berrange 21a02c
       any pending output until getting EAGAIN from write.
Daniel P. Berrange 21a02c
     - Once write returns EAGAIN, we modify the epoll event
Daniel P. Berrange 21a02c
       mask to also look for EPOLLOUT
Daniel P. Berrange 21a02c
    
Daniel P. Berrange 21a02c
    * src/lxc/lxc_controller.c: Avoid stalled I/O upon
Daniel P. Berrange 21a02c
      connected to an LXC console
Daniel P. Berrange 21a02c
Daniel P. Berrange 21a02c
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
Daniel P. Berrange 21a02c
index bb936ee..49727dd 100644
Daniel P. Berrange 21a02c
--- a/src/lxc/lxc_controller.c
Daniel P. Berrange 21a02c
+++ b/src/lxc/lxc_controller.c
Daniel P. Berrange 21a02c
@@ -736,9 +736,17 @@ struct lxcConsole {
Daniel P. Berrange 21a02c
     int hostWatch;
Daniel P. Berrange 21a02c
     int hostFd;  /* PTY FD in the host OS */
Daniel P. Berrange 21a02c
     bool hostClosed;
Daniel P. Berrange 21a02c
+    int hostEpoll;
Daniel P. Berrange 21a02c
+    bool hostBlocking;
Daniel P. Berrange 21a02c
+
Daniel P. Berrange 21a02c
     int contWatch;
Daniel P. Berrange 21a02c
     int contFd;  /* PTY FD in the container */
Daniel P. Berrange 21a02c
     bool contClosed;
Daniel P. Berrange 21a02c
+    int contEpoll;
Daniel P. Berrange 21a02c
+    bool contBlocking;
Daniel P. Berrange 21a02c
+
Daniel P. Berrange 21a02c
+    int epollWatch;
Daniel P. Berrange 21a02c
+    int epollFd; /* epoll FD for dealing with EOF */
Daniel P. Berrange 21a02c
 
Daniel P. Berrange 21a02c
     size_t fromHostLen;
Daniel P. Berrange 21a02c
     char fromHostBuf[1024];
Daniel P. Berrange 21a02c
@@ -834,102 +842,148 @@ static void lxcConsoleUpdateWatch(struct lxcConsole *console)
Daniel P. Berrange 21a02c
     int hostEvents = 0;
Daniel P. Berrange 21a02c
     int contEvents = 0;
Daniel P. Berrange 21a02c
 
Daniel P. Berrange 21a02c
-    if (!console->hostClosed) {
Daniel P. Berrange 21a02c
+    if (!console->hostClosed || (!console->hostBlocking && console->fromContLen)) {
Daniel P. Berrange 21a02c
         if (console->fromHostLen < sizeof(console->fromHostBuf))
Daniel P. Berrange 21a02c
             hostEvents |= VIR_EVENT_HANDLE_READABLE;
Daniel P. Berrange 21a02c
         if (console->fromContLen)
Daniel P. Berrange 21a02c
             hostEvents |= VIR_EVENT_HANDLE_WRITABLE;
Daniel P. Berrange 21a02c
     }
Daniel P. Berrange 21a02c
-    if (!console->contClosed) {
Daniel P. Berrange 21a02c
+    if (!console->contClosed || (!console->contBlocking && console->fromHostLen)) {
Daniel P. Berrange 21a02c
         if (console->fromContLen < sizeof(console->fromContBuf))
Daniel P. Berrange 21a02c
             contEvents |= VIR_EVENT_HANDLE_READABLE;
Daniel P. Berrange 21a02c
         if (console->fromHostLen)
Daniel P. Berrange 21a02c
             contEvents |= VIR_EVENT_HANDLE_WRITABLE;
Daniel P. Berrange 21a02c
     }
Daniel P. Berrange 21a02c
 
Daniel P. Berrange 21a02c
+    VIR_DEBUG("Container watch %d=%d host watch %d=%d",
Daniel P. Berrange 21a02c
+              console->contWatch, contEvents,
Daniel P. Berrange 21a02c
+              console->hostWatch, hostEvents);
Daniel P. Berrange 21a02c
     virEventUpdateHandle(console->contWatch, contEvents);
Daniel P. Berrange 21a02c
     virEventUpdateHandle(console->hostWatch, hostEvents);
Daniel P. Berrange 21a02c
-}
Daniel P. Berrange 21a02c
 
Daniel P. Berrange 21a02c
+    if (console->hostClosed) {
Daniel P. Berrange 21a02c
+        int events = EPOLLIN | EPOLLET;
Daniel P. Berrange 21a02c
+        if (console->hostBlocking)
Daniel P. Berrange 21a02c
+            events |= EPOLLOUT;
Daniel P. Berrange 21a02c
 
Daniel P. Berrange 21a02c
-struct lxcConsoleEOFData {
Daniel P. Berrange 21a02c
-    struct lxcConsole *console;
Daniel P. Berrange 21a02c
-    int fd;
Daniel P. Berrange 21a02c
-};
Daniel P. Berrange 21a02c
-
Daniel P. Berrange 21a02c
+        if (events != console->hostEpoll) {
Daniel P. Berrange 21a02c
+            struct epoll_event event;
Daniel P. Berrange 21a02c
+            int action = EPOLL_CTL_ADD;
Daniel P. Berrange 21a02c
+            if (console->hostEpoll)
Daniel P. Berrange 21a02c
+                action = EPOLL_CTL_MOD;
Daniel P. Berrange 21a02c
 
Daniel P. Berrange 21a02c
-static void lxcConsoleEOFThread(void *opaque)
Daniel P. Berrange 21a02c
-{
Daniel P. Berrange 21a02c
-    struct lxcConsoleEOFData *data = opaque;
Daniel P. Berrange 21a02c
-    int ret;
Daniel P. Berrange 21a02c
-    int epollfd = -1;
Daniel P. Berrange 21a02c
-    struct epoll_event event;
Daniel P. Berrange 21a02c
+            VIR_DEBUG("newHostEvents=%x oldHostEvents=%x", events, console->hostEpoll);
Daniel P. Berrange 21a02c
 
Daniel P. Berrange 21a02c
-    if ((epollfd = epoll_create(2)) < 0) {
Daniel P. Berrange 21a02c
-        virReportSystemError(errno, "%s",
Daniel P. Berrange 21a02c
-                             _("Unable to create epoll fd"));
Daniel P. Berrange 21a02c
-        goto cleanup;
Daniel P. Berrange 21a02c
+            event.events = events;
Daniel P. Berrange 21a02c
+            event.data.fd = console->hostFd;
Daniel P. Berrange 21a02c
+            if (epoll_ctl(console->epollFd, action, console->hostFd, &event) < 0) {
Daniel P. Berrange 21a02c
+                VIR_DEBUG(":fail");
Daniel P. Berrange 21a02c
+                virReportSystemError(errno, "%s",
Daniel P. Berrange 21a02c
+                                     _("Unable to add epoll fd"));
Daniel P. Berrange 21a02c
+                quit = true;
Daniel P. Berrange 21a02c
+                goto cleanup;
Daniel P. Berrange 21a02c
+            }
Daniel P. Berrange 21a02c
+            console->hostEpoll = events;
Daniel P. Berrange 21a02c
+            VIR_DEBUG("newHostEvents=%x oldHostEvents=%x", events, console->hostEpoll);
Daniel P. Berrange 21a02c
+        }
Daniel P. Berrange 21a02c
+    } else if (console->hostEpoll) {
Daniel P. Berrange 21a02c
+        VIR_DEBUG("Stop epoll oldContEvents=%x", console->hostEpoll);
Daniel P. Berrange 21a02c
+        if (epoll_ctl(console->epollFd, EPOLL_CTL_DEL, console->hostFd, NULL) < 0) {
Daniel P. Berrange 21a02c
+            virReportSystemError(errno, "%s",
Daniel P. Berrange 21a02c
+                                 _("Unable to remove epoll fd"));
Daniel P. Berrange 21a02c
+                VIR_DEBUG(":fail");
Daniel P. Berrange 21a02c
+            quit = true;
Daniel P. Berrange 21a02c
+            goto cleanup;
Daniel P. Berrange 21a02c
+        }
Daniel P. Berrange 21a02c
+        console->hostEpoll = 0;
Daniel P. Berrange 21a02c
     }
Daniel P. Berrange 21a02c
 
Daniel P. Berrange 21a02c
-    event.events = EPOLLIN | EPOLLET;
Daniel P. Berrange 21a02c
-    event.data.fd = data->fd;
Daniel P. Berrange 21a02c
-    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, data->fd, &event) < 0) {
Daniel P. Berrange 21a02c
-        virReportSystemError(errno, "%s",
Daniel P. Berrange 21a02c
-                             _("Unable to add epoll fd"));
Daniel P. Berrange 21a02c
-        goto cleanup;
Daniel P. Berrange 21a02c
+    if (console->contClosed) {
Daniel P. Berrange 21a02c
+        int events = EPOLLIN | EPOLLET;
Daniel P. Berrange 21a02c
+        if (console->contBlocking)
Daniel P. Berrange 21a02c
+            events |= EPOLLOUT;
Daniel P. Berrange 21a02c
+
Daniel P. Berrange 21a02c
+        if (events != console->contEpoll) {
Daniel P. Berrange 21a02c
+            struct epoll_event event;
Daniel P. Berrange 21a02c
+            int action = EPOLL_CTL_ADD;
Daniel P. Berrange 21a02c
+            if (console->contEpoll)
Daniel P. Berrange 21a02c
+                action = EPOLL_CTL_MOD;
Daniel P. Berrange 21a02c
+
Daniel P. Berrange 21a02c
+            VIR_DEBUG("newContEvents=%x oldContEvents=%x", events, console->contEpoll);
Daniel P. Berrange 21a02c
+
Daniel P. Berrange 21a02c
+            event.events = events;
Daniel P. Berrange 21a02c
+            event.data.fd = console->contFd;
Daniel P. Berrange 21a02c
+            if (epoll_ctl(console->epollFd, action, console->contFd, &event) < 0) {
Daniel P. Berrange 21a02c
+                virReportSystemError(errno, "%s",
Daniel P. Berrange 21a02c
+                                     _("Unable to add epoll fd"));
Daniel P. Berrange 21a02c
+                VIR_DEBUG(":fail");
Daniel P. Berrange 21a02c
+                quit = true;
Daniel P. Berrange 21a02c
+                goto cleanup;
Daniel P. Berrange 21a02c
+            }
Daniel P. Berrange 21a02c
+            console->contEpoll = events;
Daniel P. Berrange 21a02c
+            VIR_DEBUG("newHostEvents=%x oldHostEvents=%x", events, console->contEpoll);
Daniel P. Berrange 21a02c
+        }
Daniel P. Berrange 21a02c
+    } else if (console->contEpoll) {
Daniel P. Berrange 21a02c
+        VIR_DEBUG("Stop epoll oldContEvents=%x", console->contEpoll);
Daniel P. Berrange 21a02c
+        if (epoll_ctl(console->epollFd, EPOLL_CTL_DEL, console->contFd, NULL) < 0) {
Daniel P. Berrange 21a02c
+            virReportSystemError(errno, "%s",
Daniel P. Berrange 21a02c
+                                 _("Unable to remove epoll fd"));
Daniel P. Berrange 21a02c
+                VIR_DEBUG(":fail");
Daniel P. Berrange 21a02c
+            quit = true;
Daniel P. Berrange 21a02c
+            goto cleanup;
Daniel P. Berrange 21a02c
+        }
Daniel P. Berrange 21a02c
+        console->contEpoll = 0;
Daniel P. Berrange 21a02c
     }
Daniel P. Berrange 21a02c
+cleanup:
Daniel P. Berrange 21a02c
+    return;
Daniel P. Berrange 21a02c
+}
Daniel P. Berrange 21a02c
+
Daniel P. Berrange 21a02c
 
Daniel P. Berrange 21a02c
-    for (;;) {
Daniel P. Berrange 21a02c
-        ret = epoll_wait(epollfd, &event, 1, -1);
Daniel P. Berrange 21a02c
+static void lxcEpollIO(int watch, int fd, int events, void *opaque)
Daniel P. Berrange 21a02c
+{
Daniel P. Berrange 21a02c
+    struct lxcConsole *console = opaque;
Daniel P. Berrange 21a02c
+
Daniel P. Berrange 21a02c
+    virMutexLock(&lock);
Daniel P. Berrange 21a02c
+    VIR_DEBUG("IO event watch=%d fd=%d events=%d fromHost=%zu fromcont=%zu",
Daniel P. Berrange 21a02c
+              watch, fd, events,
Daniel P. Berrange 21a02c
+              console->fromHostLen,
Daniel P. Berrange 21a02c
+              console->fromContLen);
Daniel P. Berrange 21a02c
+
Daniel P. Berrange 21a02c
+    while (1) {
Daniel P. Berrange 21a02c
+        struct epoll_event event;
Daniel P. Berrange 21a02c
+        int ret;
Daniel P. Berrange 21a02c
+        ret = epoll_wait(console->epollFd, &event, 1, 0);
Daniel P. Berrange 21a02c
         if (ret < 0) {
Daniel P. Berrange 21a02c
             if (ret == EINTR)
Daniel P. Berrange 21a02c
                 continue;
Daniel P. Berrange 21a02c
             virReportSystemError(errno, "%s",
Daniel P. Berrange 21a02c
                                  _("Unable to wait on epoll"));
Daniel P. Berrange 21a02c
-            virMutexLock(&lock);
Daniel P. Berrange 21a02c
             quit = true;
Daniel P. Berrange 21a02c
-            virMutexUnlock(&lock);
Daniel P. Berrange 21a02c
             goto cleanup;
Daniel P. Berrange 21a02c
         }
Daniel P. Berrange 21a02c
 
Daniel P. Berrange 21a02c
+        if (ret == 0)
Daniel P. Berrange 21a02c
+            break;
Daniel P. Berrange 21a02c
+
Daniel P. Berrange 21a02c
+        VIR_DEBUG("fd=%d hostFd=%d contFd=%d hostEpoll=%x contEpoll=%x",
Daniel P. Berrange 21a02c
+                  event.data.fd, console->hostFd, console->contFd,
Daniel P. Berrange 21a02c
+                  console->hostEpoll, console->contEpoll);
Daniel P. Berrange 21a02c
+
Daniel P. Berrange 21a02c
         /* If we get HUP+dead PID, we just re-enable the main loop
Daniel P. Berrange 21a02c
          * which will see the PID has died and exit */
Daniel P. Berrange 21a02c
         if ((event.events & EPOLLIN)) {
Daniel P. Berrange 21a02c
-            virMutexLock(&lock);
Daniel P. Berrange 21a02c
-            if (event.data.fd == data->console->hostFd) {
Daniel P. Berrange 21a02c
-                data->console->hostClosed = false;
Daniel P. Berrange 21a02c
+            if (event.data.fd == console->hostFd) {
Daniel P. Berrange 21a02c
+                console->hostClosed = false;
Daniel P. Berrange 21a02c
             } else {
Daniel P. Berrange 21a02c
-                data->console->contClosed = false;
Daniel P. Berrange 21a02c
+                console->contClosed = false;
Daniel P. Berrange 21a02c
             }
Daniel P. Berrange 21a02c
-            lxcConsoleUpdateWatch(data->console);
Daniel P. Berrange 21a02c
-            virMutexUnlock(&lock);
Daniel P. Berrange 21a02c
+            lxcConsoleUpdateWatch(console);
Daniel P. Berrange 21a02c
             break;
Daniel P. Berrange 21a02c
         }
Daniel P. Berrange 21a02c
     }
Daniel P. Berrange 21a02c
 
Daniel P. Berrange 21a02c
 cleanup:
Daniel P. Berrange 21a02c
-    VIR_FORCE_CLOSE(epollfd);
Daniel P. Berrange 21a02c
-    VIR_FREE(data);
Daniel P. Berrange 21a02c
-}
Daniel P. Berrange 21a02c
-
Daniel P. Berrange 21a02c
-static int lxcCheckEOF(struct lxcConsole *console, int fd)
Daniel P. Berrange 21a02c
-{
Daniel P. Berrange 21a02c
-    struct lxcConsoleEOFData *data;
Daniel P. Berrange 21a02c
-    virThread thread;
Daniel P. Berrange 21a02c
-
Daniel P. Berrange 21a02c
-    if (VIR_ALLOC(data) < 0) {
Daniel P. Berrange 21a02c
-        virReportOOMError();
Daniel P. Berrange 21a02c
-        return -1;
Daniel P. Berrange 21a02c
-    }
Daniel P. Berrange 21a02c
-
Daniel P. Berrange 21a02c
-    data->console = console;
Daniel P. Berrange 21a02c
-    data->fd = fd;
Daniel P. Berrange 21a02c
-
Daniel P. Berrange 21a02c
-    if (virThreadCreate(&thread, false, lxcConsoleEOFThread, data) < 0) {
Daniel P. Berrange 21a02c
-        VIR_FREE(data);
Daniel P. Berrange 21a02c
-        return -1;
Daniel P. Berrange 21a02c
-    }
Daniel P. Berrange 21a02c
-    return 0;
Daniel P. Berrange 21a02c
+    virMutexUnlock(&lock);
Daniel P. Berrange 21a02c
 }
Daniel P. Berrange 21a02c
 
Daniel P. Berrange 21a02c
 static void lxcConsoleIO(int watch, int fd, int events, void *opaque)
Daniel P. Berrange 21a02c
@@ -937,6 +991,10 @@ static void lxcConsoleIO(int watch, int fd, int events, void *opaque)
Daniel P. Berrange 21a02c
     struct lxcConsole *console = opaque;
Daniel P. Berrange 21a02c
 
Daniel P. Berrange 21a02c
     virMutexLock(&lock);
Daniel P. Berrange 21a02c
+    VIR_DEBUG("IO event watch=%d fd=%d events=%d fromHost=%zu fromcont=%zu",
Daniel P. Berrange 21a02c
+              watch, fd, events,
Daniel P. Berrange 21a02c
+              console->fromHostLen,
Daniel P. Berrange 21a02c
+              console->fromContLen);
Daniel P. Berrange 21a02c
     if (events & VIR_EVENT_HANDLE_READABLE) {
Daniel P. Berrange 21a02c
         char *buf;
Daniel P. Berrange 21a02c
         size_t *len;
Daniel P. Berrange 21a02c
@@ -993,6 +1051,10 @@ static void lxcConsoleIO(int watch, int fd, int events, void *opaque)
Daniel P. Berrange 21a02c
             *len -= done;
Daniel P. Berrange 21a02c
         } else {
Daniel P. Berrange 21a02c
             VIR_DEBUG("Write fd %d done %d errno %d", fd, (int)done, errno);
Daniel P. Berrange 21a02c
+            if (watch == console->hostWatch)
Daniel P. Berrange 21a02c
+                console->hostBlocking = true;
Daniel P. Berrange 21a02c
+            else
Daniel P. Berrange 21a02c
+                console->contBlocking = true;
Daniel P. Berrange 21a02c
         }
Daniel P. Berrange 21a02c
     }
Daniel P. Berrange 21a02c
 
Daniel P. Berrange 21a02c
@@ -1003,8 +1065,6 @@ static void lxcConsoleIO(int watch, int fd, int events, void *opaque)
Daniel P. Berrange 21a02c
             console->contClosed = true;
Daniel P. Berrange 21a02c
         }
Daniel P. Berrange 21a02c
         VIR_DEBUG("Got EOF on %d %d", watch, fd);
Daniel P. Berrange 21a02c
-        if (lxcCheckEOF(console, fd) < 0)
Daniel P. Berrange 21a02c
-            goto error;
Daniel P. Berrange 21a02c
     }
Daniel P. Berrange 21a02c
 
Daniel P. Berrange 21a02c
     lxcConsoleUpdateWatch(console);
Daniel P. Berrange 21a02c
@@ -1103,9 +1163,32 @@ static int lxcControllerMain(int serverFd,
Daniel P. Berrange 21a02c
     }
Daniel P. Berrange 21a02c
 
Daniel P. Berrange 21a02c
     for (i = 0 ; i < nFds ; i++) {
Daniel P. Berrange 21a02c
+        consoles[i].epollFd = -1;
Daniel P. Berrange 21a02c
+        consoles[i].epollWatch = -1;
Daniel P. Berrange 21a02c
+        consoles[i].hostWatch = -1;
Daniel P. Berrange 21a02c
+        consoles[i].contWatch = -1;
Daniel P. Berrange 21a02c
+    }
Daniel P. Berrange 21a02c
+
Daniel P. Berrange 21a02c
+    for (i = 0 ; i < nFds ; i++) {
Daniel P. Berrange 21a02c
         consoles[i].hostFd = hostFds[i];
Daniel P. Berrange 21a02c
         consoles[i].contFd = contFds[i];
Daniel P. Berrange 21a02c
 
Daniel P. Berrange 21a02c
+        if ((consoles[i].epollFd = epoll_create1(EPOLL_CLOEXEC)) < 0) {
Daniel P. Berrange 21a02c
+            virReportSystemError(errno, "%s",
Daniel P. Berrange 21a02c
+                                 _("Unable to create epoll fd"));
Daniel P. Berrange 21a02c
+            goto cleanup;
Daniel P. Berrange 21a02c
+        }
Daniel P. Berrange 21a02c
+
Daniel P. Berrange 21a02c
+        if ((consoles[i].epollWatch = virEventAddHandle(consoles[i].epollFd,
Daniel P. Berrange 21a02c
+                                                        VIR_EVENT_HANDLE_READABLE,
Daniel P. Berrange 21a02c
+                                                        lxcEpollIO,
Daniel P. Berrange 21a02c
+                                                        &consoles[i],
Daniel P. Berrange 21a02c
+                                                        NULL)) < 0) {
Daniel P. Berrange 21a02c
+            lxcError(VIR_ERR_INTERNAL_ERROR, "%s",
Daniel P. Berrange 21a02c
+                     _("Unable to watch epoll FD"));
Daniel P. Berrange 21a02c
+            goto cleanup;
Daniel P. Berrange 21a02c
+        }
Daniel P. Berrange 21a02c
+
Daniel P. Berrange 21a02c
         if ((consoles[i].hostWatch = virEventAddHandle(consoles[i].hostFd,
Daniel P. Berrange 21a02c
                                                        VIR_EVENT_HANDLE_READABLE,
Daniel P. Berrange 21a02c
                                                        lxcConsoleIO,
Daniel P. Berrange 21a02c
@@ -1146,6 +1229,17 @@ cleanup:
Daniel P. Berrange 21a02c
 cleanup2:
Daniel P. Berrange 21a02c
     VIR_FORCE_CLOSE(monitor.serverFd);
Daniel P. Berrange 21a02c
     VIR_FORCE_CLOSE(monitor.clientFd);
Daniel P. Berrange 21a02c
+
Daniel P. Berrange 21a02c
+    for (i = 0 ; i < nFds ; i++) {
Daniel P. Berrange 21a02c
+        if (consoles[i].epollWatch != -1)
Daniel P. Berrange 21a02c
+            virEventRemoveHandle(consoles[i].epollWatch);
Daniel P. Berrange 21a02c
+        VIR_FORCE_CLOSE(consoles[i].epollFd);
Daniel P. Berrange 21a02c
+        if (consoles[i].contWatch != -1)
Daniel P. Berrange 21a02c
+            virEventRemoveHandle(consoles[i].contWatch);
Daniel P. Berrange 21a02c
+        if (consoles[i].hostWatch != -1)
Daniel P. Berrange 21a02c
+            virEventRemoveHandle(consoles[i].hostWatch);
Daniel P. Berrange 21a02c
+    }
Daniel P. Berrange 21a02c
+
Daniel P. Berrange 21a02c
     VIR_FREE(consoles);
Daniel P. Berrange 21a02c
     return rc;
Daniel P. Berrange 21a02c
 }