[CRIU] [PATCH 1/2] --freeze-cgroup: should also seize tasks in sub-cgroups

Tycho Andersen tycho.andersen at canonical.com
Thu Nov 19 08:15:59 PST 2015


Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
CC: Andrew Vagin <avagin at virtuozzo.com>
---
 seize.c | 124 +++++++++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 84 insertions(+), 40 deletions(-)

diff --git a/seize.c b/seize.c
index 943f9d1..3281dd0 100644
--- a/seize.c
+++ b/seize.c
@@ -79,12 +79,93 @@ static int freezer_restore_state(void)
 	return 0;
 }
 
+static int seize_cgroup_tree(char *root_path, const char *state)
+{
+	DIR *dir;
+	struct dirent *de;
+	char path[PATH_MAX];
+	FILE *f;
+
+	/*
+	 * 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", root_path);
+	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;
+		int ret;
+
+		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 */
+			pr_err("zombie found while seizing\n");
+			fclose(f);
+			return -1;
+		}
+	}
+	fclose(f);
+
+	dir = opendir(root_path);
+	if (!dir) {
+		pr_perror("Unable to open %s", root_path);
+		return -1;
+	}
+
+	while ((de = readdir(dir))) {
+		struct stat st;
+
+		if (dir_dots(de))
+			continue;
+
+		sprintf(path, "%s/%s", root_path, de->d_name);
+
+		if (fstatat(dirfd(dir), de->d_name, &st, 0) < 0) {
+			pr_perror("stat of %s failed", path);
+			closedir(dir);
+			return -1;
+		}
+
+		if (!S_ISDIR(st.st_mode))
+			continue;
+
+		if (seize_cgroup_tree(path, state) < 0) {
+			closedir(dir);
+			return -1;
+		}
+	}
+	closedir(dir);
+
+	return 0;
+}
+
 static int freeze_processes(void)
 {
-	int i, ret, fd, exit_code = -1;
+	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);
@@ -117,45 +198,8 @@ static int freeze_processes(void)
 		struct timespec req = {};
 		u64 timeout;
 
-		/*
-		 * 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 (seize_cgroup_tree(opts.freeze_cgroup, state) < 0)
 			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;
-- 
2.6.2



More information about the CRIU mailing list