From 96ce6d60417ddf6c09d7e9a2b82421adcb01652f Mon Sep 17 00:00:00 2001 From: Alex Fang Date: Sat, 6 May 2017 21:34:32 +1000 Subject: [PATCH] runc:Pass back the pid of runc:[1:CHILD] so we can wait on it reason:This allows the libcontainer to automatically clean up runc:[1:CHILD] processes created as part of nsenter. Change-Id: Ib3641cf54b5c8b830bc01fa60b3cfdcc189ea660 Signed-off-by: Alex Fang --- libcontainer/init_linux.go | 3 ++- libcontainer/nsenter/nsexec.c | 17 +++++++++++------ libcontainer/process_linux.go | 27 ++++++++++++++++++++++----- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/libcontainer/init_linux.go b/libcontainer/init_linux.go index 99cc02c..2a93431 100644 --- a/libcontainer/init_linux.go +++ b/libcontainer/init_linux.go @@ -29,7 +29,8 @@ const ( ) type pid struct { - Pid int `json:"pid"` + Pid int `json:"pid"` + PidFirstChild int `json:"pid_first"` } // network is an internal struct used to setup container networks. diff --git a/libcontainer/nsenter/nsexec.c b/libcontainer/nsenter/nsexec.c index 64ed76f..4f73b1a 100644 --- a/libcontainer/nsenter/nsexec.c +++ b/libcontainer/nsenter/nsexec.c @@ -554,7 +554,7 @@ void nsexec(void) */ case JUMP_PARENT: { int len; - pid_t child; + pid_t child, first_child = -1; char buf[JSON_MAX]; bool ready = false; @@ -618,18 +618,18 @@ void nsexec(void) } break; case SYNC_RECVPID_PLS: { - pid_t old = child; + first_child = child; /* Get the init_func pid. */ if (read(syncfd, &child, sizeof(child)) != sizeof(child)) { - kill(old, SIGKILL); + kill(first_child, SIGKILL); bail("failed to sync with child: read(childpid)"); } /* Send ACK. */ s = SYNC_RECVPID_ACK; if (write(syncfd, &s, sizeof(s)) != sizeof(s)) { - kill(old, SIGKILL); + kill(first_child, SIGKILL); kill(child, SIGKILL); bail("failed to sync with child: write(SYNC_RECVPID_ACK)"); } @@ -677,8 +677,13 @@ void nsexec(void) } } - /* Send the init_func pid back to our parent. */ - len = snprintf(buf, JSON_MAX, "{\"pid\": %d}\n", child); + /* + * Send the init_func pid and the pid of the first child back to our parent. + * + * We need to send both back because we can't reap the first child we created (CLONE_PARENT). + * It becomes the responsibility of our parent to reap the first child. + */ + len = snprintf(buf, JSON_MAX, "{\"pid\": %d, \"pid_first\": %d}\n", child, first_child); if (len < 0) { kill(child, SIGKILL); bail("unable to generate JSON for child pid"); diff --git a/libcontainer/process_linux.go b/libcontainer/process_linux.go index 7a3da4f..25fe30b 100644 --- a/libcontainer/process_linux.go +++ b/libcontainer/process_linux.go @@ -6,17 +6,18 @@ import ( "encoding/json" "errors" "fmt" - "github.com/Sirupsen/logrus" - "github.com/opencontainers/runc/libcontainer/cgroups" - "github.com/opencontainers/runc/libcontainer/configs" - "github.com/opencontainers/runc/libcontainer/system" - "github.com/opencontainers/runc/libcontainer/utils" "io" "os" "os/exec" "path/filepath" "strconv" "syscall" + + "github.com/Sirupsen/logrus" + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/runc/libcontainer/utils" "golang.org/x/sys/unix" ) @@ -141,6 +142,14 @@ func (p *setnsProcess) execSetns() error { p.cmd.Wait() return newSystemErrorWithCause(err, "reading pid from init pipe") } + + // Clean up the zombie parent process + // On Unix systems FindProcess always succeeds. + firstChildProcess, _ := os.FindProcess(pid.PidFirstChild) + + // Ignore the error in case the child has already been reaped for any reason + _, _ = firstChildProcess.Wait() + process, err := os.FindProcess(pid.Pid) if err != nil { return err @@ -224,6 +233,14 @@ func (p *initProcess) execSetns() error { p.cmd.Wait() return err } + + // Clean up the zombie parent process + // On Unix systems FindProcess always succeeds. + firstChildProcess, _ := os.FindProcess(pid.PidFirstChild) + + // Ignore the error in case the child has already been reaped for any reason + _, _ = firstChildProcess.Wait() + process, err := os.FindProcess(pid.Pid) if err != nil { return err -- 1.8.3.1