From 9946e299af9e911a54c83626f245dff20127e442 Mon Sep 17 00:00:00 2001 From: "Daniel, Dao Quang Minh" Date: Thu, 8 Jan 2015 02:27:49 -0500 Subject: [PATCH 1/3] nsenter waits for parent signal before forking this allows the parent to place the process into cgroup first so it can track the children properly Docker-DCO-1.1-Signed-off-by: Daniel, Dao Quang Minh (github: dqminh) --- namespaces/execin.go | 5 +++++ namespaces/nsenter/nsenter.c | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/namespaces/execin.go b/namespaces/execin.go index 7ce82c81..ddff5c3a 100644 --- a/namespaces/execin.go +++ b/namespaces/execin.go @@ -73,6 +73,11 @@ func ExecIn(container *libcontainer.Config, state *libcontainer.State, userArgs return terminate(err) } + // finish cgroups' setup, unblock the child process. + if _, err := parent.WriteString("1"); err != nil { + return terminate(err) + } + if err := json.NewEncoder(parent).Encode(container); err != nil { return terminate(err) } diff --git a/namespaces/nsenter/nsenter.c b/namespaces/nsenter/nsenter.c index 9782702d..1666eff8 100644 --- a/namespaces/nsenter/nsenter.c +++ b/namespaces/nsenter/nsenter.c @@ -155,6 +155,12 @@ void nsenter() exit(1); } } + // blocking until the parent placed the process inside correct cgroups. + unsigned char s; + if (read(3, &s, 1) != 1 || s != '1') { + pr_perror("failed to receive synchronization data from parent"); + exit(1); + } // Setns on all supported namespaces. char ns_dir[PATH_MAX]; memset(ns_dir, 0, PATH_MAX); From f5dfd9a702ad163be35023fe08c9573a614d6121 Mon Sep 17 00:00:00 2001 From: "Daniel, Dao Quang Minh" Date: Fri, 16 Jan 2015 04:58:30 -0500 Subject: [PATCH 2/3] nit: reindent with indent -linux Signed-off-by: Daniel, Dao Quang Minh --- namespaces/nsenter/nsenter.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/namespaces/nsenter/nsenter.c b/namespaces/nsenter/nsenter.c index 1666eff8..4ab21774 100644 --- a/namespaces/nsenter/nsenter.c +++ b/namespaces/nsenter/nsenter.c @@ -28,7 +28,6 @@ void get_args(int *argc, char ***argv) pr_perror("Unable to open /proc/self/cmdline"); exit(1); } - // Read the whole commandline. ssize_t contents_size = 0; ssize_t contents_offset = 0; @@ -98,13 +97,12 @@ void nsenter() if (strncmp(argv[0], kNsEnter, strlen(kNsEnter)) != 0) { return; } - - #ifdef PR_SET_CHILD_SUBREAPER +#ifdef PR_SET_CHILD_SUBREAPER if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0) == -1) { pr_perror("Failed to set child subreaper"); exit(1); } - #endif +#endif static const struct option longopts[] = { {"nspid", required_argument, NULL, 'n'}, @@ -134,7 +132,7 @@ void nsenter() init_pid = strtol(init_pid_str, NULL, 10); if ((init_pid == 0 && errno == EINVAL) || errno == ERANGE) { pr_perror("Failed to parse PID from \"%s\" with output \"%d\"", - init_pid_str, init_pid); + init_pid_str, init_pid); print_usage(); exit(1); } @@ -179,18 +177,19 @@ void nsenter() for (i = 0; i < num; i++) { // A zombie process has links on namespaces, but they can't be opened struct stat st; - if (fstatat(ns_dir_fd, namespaces[i], &st, AT_SYMLINK_NOFOLLOW) == -1) { + if (fstatat(ns_dir_fd, namespaces[i], &st, AT_SYMLINK_NOFOLLOW) + == -1) { if (errno == ENOENT) continue; pr_perror("Failed to stat ns file %s for ns %s", - ns_dir, namespaces[i]); + ns_dir, namespaces[i]); exit(1); } int fd = openat(ns_dir_fd, namespaces[i], O_RDONLY); if (fd == -1) { pr_perror("Failed to open ns file %s for ns %s", - ns_dir, namespaces[i]); + ns_dir, namespaces[i]); exit(1); } // Set the namespace. From 5a87153824b838be92503b57e76e96519b84b522 Mon Sep 17 00:00:00 2001 From: "Daniel, Dao Quang Minh" Date: Fri, 16 Jan 2015 05:13:19 -0500 Subject: [PATCH 3/3] fix TestNsenterAlivePid unblock the nsenter-exec test process to let it finish succesfully Signed-off-by: Daniel, Dao Quang Minh --- namespaces/nsenter/nsenter_test.go | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/namespaces/nsenter/nsenter_test.go b/namespaces/nsenter/nsenter_test.go index 85ee5d67..14870c45 100644 --- a/namespaces/nsenter/nsenter_test.go +++ b/namespaces/nsenter/nsenter_test.go @@ -12,15 +12,29 @@ import ( func TestNsenterAlivePid(t *testing.T) { args := []string{"nsenter-exec", "--nspid", fmt.Sprintf("%d", os.Getpid())} - - cmd := &exec.Cmd{ - Path: os.Args[0], - Args: args, + r, w, err := os.Pipe() + if err != nil { + t.Fatalf("failed to create pipe %v", err) } - err := cmd.Run() - if err != nil { - t.Fatal("nsenter exits with a non-zero exit status") + cmd := &exec.Cmd{ + Path: os.Args[0], + Args: args, + ExtraFiles: []*os.File{r}, + } + + if err := cmd.Start(); err != nil { + t.Fatalf("nsenter failed to start %v", err) + } + r.Close() + + // unblock the child process + if _, err := w.WriteString("1"); err != nil { + t.Fatalf("parent failed to write synchronization data %v", err) + } + + if err := cmd.Wait(); err != nil { + t.Fatalf("nsenter exits with a non-zero exit status") } }