|
|
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 |
|