[CRIU] [PATCH] cgroup: Fix early update of @dir_name in rewrite_cgsets

Cyrill Gorcunov gorcunov at gmail.com
Wed May 18 05:32:33 PDT 2016


When we're walking over controllers and their directories
we should update the directory at the very end because
otherwise we will not match the rest of them once variable
is updated.

So I desided to simply rewrite the helper. Hopefully it
is more clear now.

Signed-off-by: Cyrill Gorcunov <gorcunov at virtuozzo.com>
---
 criu/cgroup.c | 109 ++++++++++++++++++++++++++++++++++------------------------
 1 file changed, 65 insertions(+), 44 deletions(-)

diff --git a/criu/cgroup.c b/criu/cgroup.c
index e1d5023..836ac2d 100644
--- a/criu/cgroup.c
+++ b/criu/cgroup.c
@@ -1583,67 +1583,88 @@ err:
 }
 
 static int rewrite_cgsets(CgroupEntry *cge, char **controllers, int n_controllers,
-			  char **from, char *to)
+			  char **dir_name, char *newroot)
 {
-	int i, j;
-	bool set_from = false;
+	size_t dirlen = strlen(*dir_name);
+	char *dir = *dir_name;
+	char *dirnew = NULL;
+	size_t i, j;
+
+	/*
+	 * For example we may have the following in the image:
+	 *
+	 * set
+	 * 	name "hugetlb"
+	 * 	path "/300"
+	 *
+	 * controller
+	 * 	cnames hugetlb
+	 * 	dirs
+	 * 		dirname "300"
+	 * 		properties ...
+	 *
+	 * when we're switching to a new root we need to change
+	 * @path and don't forget to update the @dirname into
+	 * new state.
+	 */
 
 	for (i = 0; i < cge->n_sets; i++) {
 		CgSetEntry *set = cge->sets[i];
+
 		for (j = 0; j < set->n_ctls; j++) {
 			CgMemberEntry *cg = set->ctls[j];
-			char *tmp = cg->path, *tmp2 = NULL;
 
+			/*
+			 * Make sure if it's same controller
+			 * and its path with stripping leading
+			 * "/" is matching to be renamed.
+			 */
 			if (!(cgroup_contains(controllers, n_controllers, cg->name) &&
-					/* +1 to get rid of leading / */
-					strstartswith(cg->path + 1, *from)))
+			      strstartswith(cg->path + 1, dir)))
 				continue;
 
-			/* If this cgset has a cgns prefix, let's use
-			 * that as the start of the root replacement.
-			 */
 			if (cg->has_cgns_prefix && cg->cgns_prefix) {
-				/* Rewrite the group dir to match the
-				 * prefix. We can do this exactly once
-				 * since we know all the tasks are in
-				 * the same cgroup ns (and thus have
-				 * the same per-controller prefix path)
-				 * since we don't support nesting.
-				 */
-				if (!set_from) {
-					set_from = true;
-					tmp2 = *from;
-					/* -1 because cgns_prefix includes leading / */
-					*from = xsprintf("%s%s", to, (*from) + cg->cgns_prefix - 1);
-				}
+				char *prev = cg->path;
 
-				cg->path = xsprintf("%s%s", to, cg->path +
-							cg->cgns_prefix);
-				cg->cgns_prefix = strlen(to);
+				cg->path = xsprintf("%s%s", newroot, cg->path + cg->cgns_prefix);
+				if (!cg->path) {
+					cg->path = prev;
+					return -ENOMEM;
+				}
+				xfree(prev);
+				cg->cgns_prefix = strlen(newroot);
+
+				if (!dirnew) {
+					/* -1 because cgns_prefix includes leading "/" */
+					dirnew = xsprintf("%s%s", newroot, dir + cg->cgns_prefix - 1);
+					if (!dirnew)
+						return -ENOMEM;
+				}
 			} else {
-				/* otherwise, use the old rewriting strategy */
-				cg->path = xsprintf("%s%s", to, cg->path +
-							strlen(*from) + 1);
-				if (!set_from) {
-					set_from = true;
-					tmp2 = *from;
-					*from = xstrdup(to);
+				char *prev = cg->path;
+				/*
+				 * If no prefix present simply rename the
+				 * root but make sure the rest of path is
+				 * untouched.
+				 */
+				cg->path = xsprintf("%s%s", newroot,
+						    cg->path + dirlen + 1);
+				if (!cg->path) {
+					cg->path = prev;
+					return -ENOMEM;
+				}
+				xfree(prev);
+				if (!dirnew) {
+					dirnew = xstrdup(newroot);
+					if (!dirnew)
+						return -ENOMEM;
 				}
 			}
-
-			if (tmp2) {
-				xfree(tmp2);
-				if (!*from)
-					return -1;
-			}
-
-			if (!cg->path)
-				return -1;
-
-			free(tmp);
 		}
-
 	}
+
+	xfree(dir);
+	*dir_name = dirnew;
 	return 0;
 }
 
-- 
2.5.5



More information about the CRIU mailing list