Pass back the pid of runc:[1:CHILD] so we can wait on it

This allows the libcontainer to automatically clean up runc:[1:CHILD]
processes created as part of nsenter.

Signed-off-by: Alex Fang <littlelightlittlefire@gmail.com>
This commit is contained in:
Alex Fang 2017-05-06 21:34:32 +10:00 committed by lllf
parent 45bde006ca
commit e92add2151
3 changed files with 33 additions and 7 deletions

View File

@ -31,7 +31,8 @@ const (
) )
type pid struct { 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. // network is an internal struct used to setup container networks.

View File

@ -542,7 +542,7 @@ void nsexec(void)
*/ */
case JUMP_PARENT: { case JUMP_PARENT: {
int len; int len;
pid_t child; pid_t child, first_child = -1;
char buf[JSON_MAX]; char buf[JSON_MAX];
bool ready = false; bool ready = false;
@ -606,18 +606,18 @@ void nsexec(void)
} }
break; break;
case SYNC_RECVPID_PLS: { case SYNC_RECVPID_PLS: {
pid_t old = child; first_child = child;
/* Get the init_func pid. */ /* Get the init_func pid. */
if (read(syncfd, &child, sizeof(child)) != sizeof(child)) { if (read(syncfd, &child, sizeof(child)) != sizeof(child)) {
kill(old, SIGKILL); kill(first_child, SIGKILL);
bail("failed to sync with child: read(childpid)"); bail("failed to sync with child: read(childpid)");
} }
/* Send ACK. */ /* Send ACK. */
s = SYNC_RECVPID_ACK; s = SYNC_RECVPID_ACK;
if (write(syncfd, &s, sizeof(s)) != sizeof(s)) { if (write(syncfd, &s, sizeof(s)) != sizeof(s)) {
kill(old, SIGKILL); kill(first_child, SIGKILL);
kill(child, SIGKILL); kill(child, SIGKILL);
bail("failed to sync with child: write(SYNC_RECVPID_ACK)"); bail("failed to sync with child: write(SYNC_RECVPID_ACK)");
} }
@ -665,8 +665,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) { if (len < 0) {
kill(child, SIGKILL); kill(child, SIGKILL);
bail("unable to generate JSON for child pid"); bail("unable to generate JSON for child pid");

View File

@ -141,6 +141,16 @@ func (p *setnsProcess) execSetns() error {
p.cmd.Wait() p.cmd.Wait()
return newSystemErrorWithCause(err, "reading pid from init pipe") return newSystemErrorWithCause(err, "reading pid from init pipe")
} }
// Clean up the zombie parent process
firstChildProcess, err := os.FindProcess(pid.PidFirstChild)
if err != nil {
return err
}
// Ignore the error in case the child has already been reaped for any reason
_, _ = firstChildProcess.Wait()
process, err := os.FindProcess(pid.Pid) process, err := os.FindProcess(pid.Pid)
if err != nil { if err != nil {
return err return err
@ -224,6 +234,16 @@ func (p *initProcess) execSetns() error {
p.cmd.Wait() p.cmd.Wait()
return err return err
} }
// Clean up the zombie parent process
firstChildProcess, err := os.FindProcess(pid.PidFirstChild)
if err != nil {
return err
}
// Ignore the error in case the child has already been reaped for any reason
_, _ = firstChildProcess.Wait()
process, err := os.FindProcess(pid.Pid) process, err := os.FindProcess(pid.Pid)
if err != nil { if err != nil {
return err return err