[CRIU] [PATCH] seize: don't wory if a cgroup contains some extra tasks (v2)

Andrey Vagin avagin at openvz.org
Fri Oct 30 06:24:54 PDT 2015


From: Andrew Vagin <avagin at openvz.org>

A freezer cgroup can contain tasks which will be not dumped,
criu unfreezes the group, so we need to freeze all extra
task with ptrace like we do for target tasks.

Currently we attache and send an interrupt signals to these tasks,
but we don't call waitpid() for them, so then waitpid(-1, ...)
returns these tasks where we don't expect to see them.

v2: execute freezer_detach() only if opts.freeze_cgroup is set
    calculate extra tasks in a freezer cgroup correctly

Signed-off-by: Andrew Vagin <avagin at openvz.org>
---
 include/ptrace.h |  2 ++
 ptrace.c         | 14 +++++++++++-
 seize.c          | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 82 insertions(+), 2 deletions(-)

diff --git a/include/ptrace.h b/include/ptrace.h
index 079ad63..a3852ce 100644
--- a/include/ptrace.h
+++ b/include/ptrace.h
@@ -67,6 +67,8 @@ struct ptrace_peeksiginfo_args {
 
 #define SI_EVENT(_si_code)	(((_si_code) & 0xFFFF) >> 8)
 
+extern int frozen_processes;
+
 extern int seize_catch_task(pid_t pid);
 extern int seize_wait_task(pid_t pid, pid_t ppid, struct proc_status_creds **creds);
 extern int suspend_seccomp(pid_t pid);
diff --git a/ptrace.c b/ptrace.c
index b28824b..a27392a 100644
--- a/ptrace.c
+++ b/ptrace.c
@@ -117,10 +117,22 @@ int seize_wait_task(pid_t pid, pid_t ppid, struct proc_status_creds **creds)
 	 * we might need at that early point.
 	 */
 
+	frozen_processes--;
 try_again:
 
 	ret = wait4(pid, &status, __WALL, NULL);
-	wait_errno = errno;
+	if (ret < 0) {
+		/*
+		 * wait4() can expectedly fail only in a first time
+		 * if a task is zombie. If we are here from try_again,
+		 * this means that we are tracing this task.
+		 *
+		 * frozen_processes should be descrimented only once in this
+		 * function if a first wait was success.
+		 */
+		frozen_processes++;
+		wait_errno = errno;
+	}
 
 	ret2 = parse_pid_status(pid, &cr);
 	if (ret2)
diff --git a/seize.c b/seize.c
index 20c0349..203042b 100644
--- a/seize.c
+++ b/seize.c
@@ -84,6 +84,63 @@ int freeze_cgroup()
 	return 0;
 }
 
+/* A number of tasks in a freezer cgroup which are not going to be dumped */
+int frozen_processes;
+
+/*
+ * A freezer cgroup can contain tasks which will not be dumped
+ * and we need to wait them, because the are interupted them by ptrace.
+ */
+static int freezer_wait_processes()
+{
+	int i;
+
+	for (i = 0; i < frozen_processes; i++) {
+		int status;
+		pid_t pid;
+
+		/*
+		 * Here we are going to skip tasks which are already traced.
+		 * Ptraced tasks looks like children for us, so if
+		 * a task isn't ptraced yet, waitpid() will return a error.
+		 */
+		pid = waitpid(-1, &status, 0);
+		if (pid < 0) {
+			pr_perror("Unable to wait processes");
+			return -1;
+		}
+		pr_warn("Unexpected process %d in the freezer cgroup (status 0x%x)\n", pid, status);
+	}
+
+	return 0;
+}
+
+static int freezer_detach(void)
+{
+	char path[PATH_MAX];
+	FILE *f;
+
+	if (!opts.freeze_cgroup || !frozen_processes)
+		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;
+
+		pid = atoi(path);
+
+		if (ptrace(PTRACE_DETACH, pid, NULL, NULL))
+			pr_perror("Unable to detach from %d\n", pid);
+	}
+	fclose(f);
+	return 0;
+}
+
 static int freeze_processes(void)
 {
 	int i, ret, fd, exit_code = -1;
@@ -146,7 +203,10 @@ static int freeze_processes(void)
 			if (ret == 0)
 				continue;
 
-			if (seize_catch_task(pid) && state == frozen) {
+			if (!seize_catch_task(pid)) {
+				pr_debug("SEIZE %d: success\n", pid);
+				frozen_processes++;
+			} else if (state == frozen) {
 				char buf[] = "/proc/XXXXXXXXXX/exe";
 				struct stat st;
 
@@ -324,6 +384,9 @@ static void pstree_wait(struct pstree_item *root_item)
 			}
 		}
 	}
+
+	if (opts.freeze_cgroup)
+		freezer_detach();
 	pid = wait4(-1, &status, __WALL, NULL);
 	if (pid > 0) {
 		pr_err("Unexpected child %d\n", pid);
@@ -536,6 +599,9 @@ int collect_pstree(pid_t pid)
 	if (ret < 0)
 		goto err;
 
+	if (opts.freeze_cgroup && freezer_wait_processes())
+		return -1;
+
 	timing_stop(TIME_FREEZING);
 	timing_start(TIME_FROZEN);
 
-- 
2.4.3



More information about the CRIU mailing list