The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/3427

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
In case the child simply dies or the client exits the fd will be closed and we
will receive a POLLNVAL event. We need to handle this case otherwise we will
keep poll()ing without ever exiting.

Closes #2964.

Signed-off-by: Christian Brauner <[email protected]>
From 32ae26b8b7ff03538ebb75e02488c0a23601ebc3 Mon Sep 17 00:00:00 2001
From: Christian Brauner <[email protected]>
Date: Mon, 19 Jun 2017 15:44:43 +0200
Subject: [PATCH] exec: detect POLLNVAL when poll()ing

In case the child simply dies or the client exits the fd will be closed and we
will receive a POLLNVAL event. We need to handle this case otherwise we will
keep poll()ing without ever exiting.

Closes #2964.

Signed-off-by: Christian Brauner <[email protected]>
---
 lxd/container_exec.go |  2 ++
 shared/util_linux.go  | 13 +++++++++----
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/lxd/container_exec.go b/lxd/container_exec.go
index 9c4359007..91d860e6a 100644
--- a/lxd/container_exec.go
+++ b/lxd/container_exec.go
@@ -227,10 +227,12 @@ func (s *execWs) Do(op *operation) error {
                        conn := s.conns[0]
                        s.connsLock.Unlock()
 
+                       logger.Debugf("Starting to mirror websocket")
                        readDone, writeDone := shared.WebsocketExecMirror(conn, 
ptys[0], ptys[0], attachedChildIsDead, int(ptys[0].Fd()))
 
                        <-readDone
                        <-writeDone
+                       logger.Debugf("Finished to mirror websocket")
 
                        conn.Close()
                        wgEOF.Done()
diff --git a/shared/util_linux.go b/shared/util_linux.go
index 66e896139..5be541c6e 100644
--- a/shared/util_linux.go
+++ b/shared/util_linux.go
@@ -570,12 +570,14 @@ func ExecReaderToChannel(r io.Reader, bufferSize int, 
exited <-chan bool, fd int
 
                atomic.StoreInt32(&attachedChildIsDead, 1)
 
-               ret, revents, err := GetPollRevents(fd, 0, (POLLIN | POLLPRI | 
POLLERR | POLLHUP | POLLRDHUP))
+               ret, revents, err := GetPollRevents(fd, 0, (POLLIN | POLLPRI | 
POLLERR | POLLHUP | POLLRDHUP | POLLNVAL))
                if ret < 0 {
                        logger.Errorf("Failed to poll(POLLIN | POLLPRI | 
POLLHUP | POLLRDHUP) on file descriptor: %s.", err)
                } else if ret > 0 {
                        if (revents & POLLERR) > 0 {
                                logger.Warnf("Detected poll(POLLERR) event.")
+                       } else if (revents & POLLNVAL) > 0 {
+                               logger.Warnf("Detected poll(POLLNVAL) event.")
                        }
                } else if ret == 0 {
                        logger.Debugf("No data in stdout: exiting.")
@@ -595,7 +597,7 @@ func ExecReaderToChannel(r io.Reader, bufferSize int, 
exited <-chan bool, fd int
                        nr := 0
                        var err error
 
-                       ret, revents, err := GetPollRevents(fd, -1, (POLLIN | 
POLLPRI | POLLERR | POLLHUP | POLLRDHUP))
+                       ret, revents, err := GetPollRevents(fd, -1, (POLLIN | 
POLLPRI | POLLERR | POLLHUP | POLLRDHUP | POLLNVAL))
                        if ret < 0 {
                                // This condition is only reached in cases 
where we are massively f*cked since we even handle
                                // EINTR in the underlying C wrapper around 
poll(). So let's exit here.
@@ -616,6 +618,9 @@ func ExecReaderToChannel(r io.Reader, bufferSize int, 
exited <-chan bool, fd int
                        if (revents & POLLERR) > 0 {
                                logger.Warnf("Detected poll(POLLERR) event: 
exiting.")
                                return
+                       } else if (revents & POLLNVAL) > 0 {
+                               logger.Warnf("Detected poll(POLLNVAL) event: 
exiting.")
+                               return
                        }
 
                        if ((revents & (POLLIN | POLLPRI)) > 0) && !both {
@@ -671,11 +676,11 @@ func ExecReaderToChannel(r io.Reader, bufferSize int, 
exited <-chan bool, fd int
                                        //   or (POLLHUP | POLLRDHUP). Both 
will trigger another codepath (See [2].)
                                        //   that takes care that all data of 
the child that is buffered in
                                        //   stdout is written out.
-                                       ret, revents, err := GetPollRevents(fd, 
0, (POLLIN | POLLPRI | POLLERR | POLLHUP | POLLRDHUP))
+                                       ret, revents, err := GetPollRevents(fd, 
0, (POLLIN | POLLPRI | POLLERR | POLLHUP | POLLRDHUP | POLLNVAL))
                                        if ret < 0 {
                                                logger.Errorf("Failed to 
poll(POLLIN | POLLPRI | POLLERR | POLLHUP | POLLRDHUP) on file descriptor: %s. 
Exiting.", err)
                                                return
-                                       } else if (revents & (POLLHUP | 
POLLRDHUP)) == 0 {
+                                       } else if (revents & (POLLHUP | 
POLLRDHUP | POLLERR | POLLNVAL)) == 0 {
                                                logger.Debugf("Exiting but 
background processes are still running.")
                                                return
                                        }
_______________________________________________
lxc-devel mailing list
[email protected]
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to