[CRIU] [PATCH] seize: detach from external processes before killing dumped processes (v2)

Andrey Vagin avagin at openvz.org
Mon Feb 8 10:32:37 PST 2016


When we kill a container, all processes from its pidns are killed by
SIGKILL, but we don't expect that someone from the freezer cgroup will
be killed too if it was not dumped.

(00.468446) Error (seize.c:439): Unexpected child 79162
(00.468489) Error (seize.c:440): BUG at seize.c:440

This situation is posiable, if someone enters into pidns by setns.

In this patch, we deatches from extra processes before killing dumped
processes. In this case, we are not get signals if someone is killed.

v2: use process_to_wait insread of adding a new var

https://jira.sw.ru/browse/PSBM-43795
Signed-off-by: Andrey Vagin <avagin at openvz.org>
Signed-off-by: Andrew Vagin <avagin at virtuozzo.com>
---
 ptrace.c |  3 ---
 seize.c  | 48 +++++++++++++++++++++++++++++-------------------
 2 files changed, 29 insertions(+), 22 deletions(-)

diff --git a/ptrace.c b/ptrace.c
index 85c7603..25970fc 100644
--- a/ptrace.c
+++ b/ptrace.c
@@ -50,9 +50,6 @@ int unseize_task(pid_t pid, int orig_st, int st)
 	} else
 		pr_err("Unknown final state %d\n", st);
 
-	if (opts.freeze_cgroup)
-		return 0;
-
 	if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) {
 		pr_perror("Unable to detach from %d", pid);
 		return -1;
diff --git a/seize.c b/seize.c
index 17ec830..7d1f77c 100644
--- a/seize.c
+++ b/seize.c
@@ -176,6 +176,7 @@ static int seize_cgroup_tree(char *root_path, const char *state)
 
 /* A number of tasks in a freezer cgroup which are not going to be dumped */
 int processes_to_wait;
+static pid_t *processes_to_wait_pids;
 
 /*
  * A freezer cgroup can contain tasks which will not be dumped
@@ -185,6 +186,10 @@ static int freezer_wait_processes()
 {
 	int i;
 
+	processes_to_wait_pids = xmalloc(sizeof(pid_t) * processes_to_wait);
+	if (processes_to_wait_pids == NULL)
+		return -1;
+
 	for (i = 0; i < processes_to_wait; i++) {
 		int status;
 		pid_t pid;
@@ -197,9 +202,12 @@ static int freezer_wait_processes()
 		pid = waitpid(-1, &status, 0);
 		if (pid < 0) {
 			pr_perror("Unable to wait processes");
+			xfree(processes_to_wait_pids);
 			return -1;
 		}
 		pr_warn("Unexpected process %d in the freezer cgroup (status 0x%x)\n", pid, status);
+
+		processes_to_wait_pids[i] = pid;
 	}
 
 	return 0;
@@ -207,27 +215,29 @@ static int freezer_wait_processes()
 
 static int freezer_detach(void)
 {
-	char path[PATH_MAX];
-	FILE *f;
+	int i;
 
 	if (!opts.freeze_cgroup)
 		return 0;
 
-	snprintf(path, sizeof(path), "%s/tasks", opts.freeze_cgroup);
-	f = fopen(path, "r");
-	if (f == NULL) {
-		pr_perror("Unable to open %s", path);
-		return -1;
-	}
-	while (fgets(path, sizeof(path), f)) {
-		pid_t pid;
+	for (i = 0; i < processes_to_wait; i++) {
+		pid_t pid = processes_to_wait_pids[i];
+		int status, save_errno;
 
-		pid = atoi(path);
+		if (ptrace(PTRACE_DETACH, pid, NULL, NULL) == 0)
+			continue;
+
+		save_errno = errno;
 
-		if (ptrace(PTRACE_DETACH, pid, NULL, NULL))
-			pr_perror("Unable to detach from %d", pid);
+		/* A process may be killed by SIGKILL */
+		if (wait4(pid, &status, __WALL, NULL) == pid) {
+			pr_warn("The %d process returned 0x %x\n", pid, status);
+			continue;
+		}
+		errno = save_errno;
+		pr_perror("Unable to detach from %d", pid);
 	}
-	fclose(f);
+
 	return 0;
 }
 
@@ -402,7 +412,7 @@ static void unseize_task_and_threads(const struct pstree_item *item, int st)
 
 	unseize_task(item->pid.real, item->state, st);
 
-	if (st == TASK_DEAD || opts.freeze_cgroup)
+	if (st == TASK_DEAD)
 		return;
 
 	for (i = 1; i < item->nr_threads; i++)
@@ -448,10 +458,6 @@ void pstree_switch_state(struct pstree_item *root_item, int st)
 	if (st != TASK_DEAD)
 		freezer_restore_state();
 
-	pr_info("Unfreezing tasks into %d\n", st);
-	for_each_pstree_item(item)
-		unseize_task_and_threads(item, st);
-
 	/*
 	 * We need to detach from all processes before waiting the init
 	 * process, because one of these processes may collect processes from a
@@ -460,6 +466,10 @@ void pstree_switch_state(struct pstree_item *root_item, int st)
 	 */
 	freezer_detach();
 
+	pr_info("Unfreezing tasks into %d\n", st);
+	for_each_pstree_item(item)
+		unseize_task_and_threads(item, st);
+
 	if (st == TASK_DEAD)
 		pstree_wait(root_item);
 }
-- 
2.4.3



More information about the CRIU mailing list