[CRIU] [PATCH 2/2] seize: don't catch all processes from a freezer cgroup

Andrey Vagin avagin at openvz.org
Tue Oct 27 04:13:21 PDT 2015


From: Andrew Vagin <avagin at openvz.org>

It can contain extra processes, but criu dumps only descendants
of a specified process.

seize_catch_task() attaches to a process and sends the interrupt signal,
then seize_wait_task() waits when a process will be interrupted.

Currently if a group contains extra processes, criu attaches to them,
but doesn't wait them, so waitpid(-1, ...) can return one of this processes,
but we don't expect this.

Reported-by: @jcarnus
Signed-off-by: Andrew Vagin <avagin at openvz.org>
---
 seize.c      | 99 +++++++++++++++++++++++++++++++++++++-----------------------
 test/zdtm.sh |  2 +-
 2 files changed, 62 insertions(+), 39 deletions(-)

diff --git a/seize.c b/seize.c
index 0f93b84..e1caebb 100644
--- a/seize.c
+++ b/seize.c
@@ -79,12 +79,68 @@ static int freezer_restore_state(void)
 	return 0;
 }
 
-static int freeze_processes(void)
+static int __freeze_processes(pid_t pid, const char *state)
 {
-	int i, ret, fd, exit_code = -1;
+	pid_t *children = NULL;
+	int nr_children = 0;
+	int ret, off = -1, exit_code = -1;
+	struct pid *threads = NULL;
+
+	while (1) {
+		int nr_threads = 0;
+		int i;
+
+		if (parse_threads(pid, &threads, &nr_threads))
+			goto err;
+
+		for (i = 0; i < nr_threads; i++) {
+			pid_t tid = threads[i].real;
+
+			/*
+			 * 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.
+			 */
+			ret = wait4(tid, NULL, __WALL | WNOHANG, NULL);
+			if (ret == 0)
+				continue;
+
+			if (seize_catch_task(tid) && state == frozen) {
+				char buf[] = "/proc/XXXXXXXXXX/exe";
+				struct stat st;
+
+				/* skip kernel threads and zombies */
+				snprintf(buf, sizeof(buf), "/proc/%d/exe", pid);
+				if (stat(buf, &st) == -1 && errno == ENOENT)
+					continue;
+
+				goto err;
+			}
+		}
+		xfree(threads);
+		threads = NULL;
+
+		if (parse_children(pid, &children, &nr_children))
+			goto err;
+
+		off++;
+		if (off >= nr_children)
+			break;
+		pid = children[off];
+	}
+
+	exit_code = 0;
+err:
+	xfree(children);
+	xfree(threads);
+	return exit_code;
+}
+
+static int freeze_processes(int pid)
+{
+	int i, fd, exit_code = -1;
 	char path[PATH_MAX];
 	const char *state = thawed;
-	FILE *f;
 
 	snprintf(path, sizeof(path), "%s/freezer.state", opts.freeze_cgroup);
 	fd = open(path, O_RDWR);
@@ -121,41 +177,8 @@ static int freeze_processes(void)
 		 * New tasks can appear while a freezer state isn't
 		 * frozen, so we need to catch all new tasks.
 		 */
-		snprintf(path, sizeof(path), "%s/tasks", opts.freeze_cgroup);
-		f = fopen(path, "r");
-		if (f == NULL) {
-			pr_perror("Unable to open %s", path);
+		if (__freeze_processes(pid, state))
 			goto err;
-		}
-		while (fgets(path, sizeof(path), f)) {
-			pid_t pid;
-
-			pid = atoi(path);
-
-			/*
-			 * 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.
-			 */
-			ret = wait4(pid, NULL, __WALL | WNOHANG, NULL);
-			if (ret == 0)
-				continue;
-
-			if (seize_catch_task(pid) && state == frozen) {
-				char buf[] = "/proc/XXXXXXXXXX/exe";
-				struct stat st;
-
-				/* skip kernel threads */
-				snprintf(buf, sizeof(buf), "/proc/%d/exe", pid);
-				if (stat(buf, &st) == -1 && errno == ENOENT)
-					continue;
-
-				/* fails when meets a zombie */
-				fclose(f);
-				goto err;
-			}
-		}
-		fclose(f);
 
 		if (state == frozen)
 			break;
@@ -507,7 +530,7 @@ int collect_pstree(pid_t pid)
 
 	timing_start(TIME_FREEZING);
 
-	if (opts.freeze_cgroup && freeze_processes())
+	if (opts.freeze_cgroup && freeze_processes(pid))
 		return -1;
 
 	root_item = alloc_pstree_item();
diff --git a/test/zdtm.sh b/test/zdtm.sh
index cf37f74..6e1ee67 100755
--- a/test/zdtm.sh
+++ b/test/zdtm.sh
@@ -794,7 +794,7 @@ EOF
 			save_fds $PID  $ddump/dump.fd
 			save_maps $PID  $ddump/dump.maps
 		}
-		setsid $CRIU_CPT $dump_cmd -D $ddump -o dump.log -v4 -t $PID $gen_args $cpt_args
+		strace -fo /tmp/strace.log -s 256 $CRIU_CPT $dump_cmd -D $ddump -o dump.log -v4 -t $PID $gen_args $cpt_args
 		retcode=$?
 
 		cat $ddump/dump.log | grep Error
-- 
2.4.3



More information about the CRIU mailing list