c401cc
From d1db5ddfebcab5075d25958dd7dfcaaf28238e72 Mon Sep 17 00:00:00 2001
c401cc
Message-Id: <d1db5ddfebcab5075d25958dd7dfcaaf28238e72.1386348946.git.jdenemar@redhat.com>
c401cc
From: "Daniel P. Berrange" <berrange@redhat.com>
c401cc
Date: Mon, 2 Dec 2013 13:37:07 +0000
c401cc
Subject: [PATCH] Fix busy wait loop in LXC container I/O handling
c401cc
c401cc
For
c401cc
c401cc
  https://bugzilla.redhat.com/show_bug.cgi?id=1032705
c401cc
c401cc
If the host side of an LXC container console disconnected
c401cc
and the guest side continued to write data, until the PTY
c401cc
buffer filled up, the LXC controller would busy wait. It
c401cc
would repeatedly see POLLHUP from poll() and not disable
c401cc
the watch.
c401cc
c401cc
This was due to some bogus logic detecting blocking
c401cc
conditions. Upon seeing a POLLHUP we must disable all
c401cc
reading & writing from the PTY, and setup the epoll to
c401cc
wake us up again when the connection comes back.
c401cc
c401cc
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
c401cc
(cherry picked from commit 5087a5a0092853702eb5e0c0297937a7859bcab3)
c401cc
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
c401cc
---
c401cc
 src/lxc/lxc_controller.c | 32 +++++++++++++++++---------------
c401cc
 1 file changed, 17 insertions(+), 15 deletions(-)
c401cc
c401cc
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
c401cc
index 5754c92..cb2db82 100644
c401cc
--- a/src/lxc/lxc_controller.c
c401cc
+++ b/src/lxc/lxc_controller.c
c401cc
@@ -77,13 +77,11 @@ struct _virLXCControllerConsole {
c401cc
     int hostFd;  /* PTY FD in the host OS */
c401cc
     bool hostClosed;
c401cc
     int hostEpoll;
c401cc
-    bool hostBlocking;
c401cc
 
c401cc
     int contWatch;
c401cc
     int contFd;  /* PTY FD in the container */
c401cc
     bool contClosed;
c401cc
     int contEpoll;
c401cc
-    bool contBlocking;
c401cc
 
c401cc
     int epollWatch;
c401cc
     int epollFd; /* epoll FD for dealing with EOF */
c401cc
@@ -805,12 +803,15 @@ static void virLXCControllerSignalChildIO(virNetServerPtr server,
c401cc
     int status;
c401cc
 
c401cc
     ret = waitpid(-1, &status, WNOHANG);
c401cc
+    VIR_DEBUG("Got sig child %d vs %lld", ret, (unsigned long long)ctrl->initpid);
c401cc
     if (ret == ctrl->initpid) {
c401cc
         virNetServerQuit(server);
c401cc
         virMutexLock(&lock);
c401cc
         if (WIFSIGNALED(status) &&
c401cc
-            WTERMSIG(status) == SIGHUP)
c401cc
+            WTERMSIG(status) == SIGHUP) {
c401cc
+            VIR_DEBUG("Status indicates reboot");
c401cc
             wantReboot = true;
c401cc
+        }
c401cc
         virMutexUnlock(&lock);
c401cc
     }
c401cc
 }
c401cc
@@ -821,28 +822,32 @@ static void virLXCControllerConsoleUpdateWatch(virLXCControllerConsolePtr consol
c401cc
     int hostEvents = 0;
c401cc
     int contEvents = 0;
c401cc
 
c401cc
-    if (!console->hostClosed || (!console->hostBlocking && console->fromContLen)) {
c401cc
+    /* If host console is open, then we can look to read/write */
c401cc
+    if (!console->hostClosed) {
c401cc
         if (console->fromHostLen < sizeof(console->fromHostBuf))
c401cc
             hostEvents |= VIR_EVENT_HANDLE_READABLE;
c401cc
         if (console->fromContLen)
c401cc
             hostEvents |= VIR_EVENT_HANDLE_WRITABLE;
c401cc
     }
c401cc
-    if (!console->contClosed || (!console->contBlocking && console->fromHostLen)) {
c401cc
+
c401cc
+    /* If cont console is open, then we can look to read/write */
c401cc
+    if (!console->contClosed) {
c401cc
         if (console->fromContLen < sizeof(console->fromContBuf))
c401cc
             contEvents |= VIR_EVENT_HANDLE_READABLE;
c401cc
         if (console->fromHostLen)
c401cc
             contEvents |= VIR_EVENT_HANDLE_WRITABLE;
c401cc
     }
c401cc
 
c401cc
-    VIR_DEBUG("Container watch %d=%d host watch %d=%d",
c401cc
-              console->contWatch, contEvents,
c401cc
-              console->hostWatch, hostEvents);
c401cc
+    VIR_DEBUG("Container watch=%d, events=%d closed=%d; host watch=%d events=%d closed=%d",
c401cc
+              console->contWatch, contEvents, console->contClosed,
c401cc
+              console->hostWatch, hostEvents, console->hostClosed);
c401cc
     virEventUpdateHandle(console->contWatch, contEvents);
c401cc
     virEventUpdateHandle(console->hostWatch, hostEvents);
c401cc
 
c401cc
     if (console->hostClosed) {
c401cc
+        /* Must setup an epoll to detect when host becomes accessible again */
c401cc
         int events = EPOLLIN | EPOLLET;
c401cc
-        if (console->hostBlocking)
c401cc
+        if (console->fromContLen)
c401cc
             events |= EPOLLOUT;
c401cc
 
c401cc
         if (events != console->hostEpoll) {
c401cc
@@ -878,8 +883,9 @@ static void virLXCControllerConsoleUpdateWatch(virLXCControllerConsolePtr consol
c401cc
     }
c401cc
 
c401cc
     if (console->contClosed) {
c401cc
+        /* Must setup an epoll to detect when guest becomes accessible again */
c401cc
         int events = EPOLLIN | EPOLLET;
c401cc
-        if (console->contBlocking)
c401cc
+        if (console->fromHostLen)
c401cc
             events |= EPOLLOUT;
c401cc
 
c401cc
         if (events != console->contEpoll) {
c401cc
@@ -950,7 +956,7 @@ static void virLXCControllerConsoleEPoll(int watch, int fd, int events, void *op
c401cc
 
c401cc
         /* If we get HUP+dead PID, we just re-enable the main loop
c401cc
          * which will see the PID has died and exit */
c401cc
-        if ((event.events & EPOLLIN)) {
c401cc
+        if ((event.events & (EPOLLIN|EPOLLOUT))) {
c401cc
             if (event.data.fd == console->hostFd) {
c401cc
                 console->hostClosed = false;
c401cc
             } else {
c401cc
@@ -1030,10 +1036,6 @@ static void virLXCControllerConsoleIO(int watch, int fd, int events, void *opaqu
c401cc
             *len -= done;
c401cc
         } else {
c401cc
             VIR_DEBUG("Write fd %d done %d errno %d", fd, (int)done, errno);
c401cc
-            if (watch == console->hostWatch)
c401cc
-                console->hostBlocking = true;
c401cc
-            else
c401cc
-                console->contBlocking = true;
c401cc
         }
c401cc
     }
c401cc
 
c401cc
-- 
c401cc
1.8.4.5
c401cc