[CRIU] [PATCH] restore: copy special cpuset props recursively

Pavel Emelyanov xemul at parallels.com
Wed Oct 1 05:33:29 PDT 2014


On 09/30/2014 11:50 PM, Tycho Andersen wrote:
> The symptom of this bug was that users restoring tasks to a nested cgroup where
> the top level group was created by criu (and not previously configured) e.g.
> cpuset:/lxc/u1 would get an ENOSPC. criu would try to copy the special
> properties into /lxc/u1 directly and (silently) fail, and then tried to copy
> the task into the cg and fail with ENOSPC:
> 
> ENOSPC Attempted  to  write(2)  an empty cpuset.cpus or cpuset.mems setting to
>        a cpuset that has tasks attached.
> 
> Fixing the silent failure to a loud failure, it gave EACCES:
> 
> EACCES Attempted to add, using write(2), a CPU or memory node to a cpuset, when
>        that CPU or memory node was not already in its parent.
> 
> So, we need to copy the the special props down the entire tree. Additionally,
> we shouldn't copy props directly from the top, since some intermediate point in
> the tree could add restrictions. We first walk back up the tree to find the
> first point where the props are empty, and then copy that parent's props all
> the way down.

Maybe the better solution would be to move the call to copy_specual_cg_props
into the prepare_cgroup_dirs and populate the e.g. cpumask right after the
directory creation?

> Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
> ---
>  cgroup.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++--------------
>  1 file changed, 88 insertions(+), 24 deletions(-)
> 
> diff --git a/cgroup.c b/cgroup.c
> index fc220c9..26b0a17 100644
> --- a/cgroup.c
> +++ b/cgroup.c
> @@ -868,42 +868,106 @@ static const char *special_cpuset_props[] = {
>  	NULL,
>  };
>  
> -static int copy_special_cg_props(const char *controller, const char *path)
> +static int find_value(const char *controller, const char *path, const char *prop,
> +			char *value, char *prefix, char *missing_path)
>  {
> -	int cg = get_service_fd(CGROUP_YARD);
> +	char fpath[PATH_MAX], my_path[PATH_MAX];
> +	char *pos;
> +	int ret, cg;
>  
> +	cg = get_service_fd(CGROUP_YARD);
> +	strncpy(my_path, path, PATH_MAX);
> +
> +	while (1) {
> +		FILE *f;
> +
> +		pos = strrchr(my_path, '/');
> +		if (pos) {
> +			*pos = 0;
> +			snprintf(prefix, PATH_MAX, "%s/%s", controller, my_path);
> +		} else {
> +			snprintf(fpath, PATH_MAX, "%s", controller);
> +		}
> +		snprintf(fpath, PATH_MAX, "%s/%s", prefix, prop);
> +
> +		f = fopenat(cg, fpath, "r");
> +		if (!f)
> +			return -1;
> +
> +		ret = fscanf(f, "%1024s", value);
> +		fclose(f);
> +
> +		if (ret > 0) {
> +			strcpy(missing_path, path + (pos - my_path));
> +			return 0;
> +		} else if (!pos) {
> +			pr_err("didn't find a value to propogate in the root!\n");
> +			return -1;
> +		}
> +	}
> +
> +	return -1;
> +}
> +
> +static int copy_recursive(const char *prefix, char *path, const char *prop, const char *value)
> +{
> +	char fpath[PATH_MAX];
> +	char *pos;
> +	int ret, out, cg;
> +
> +	cg = get_service_fd(CGROUP_YARD);
> +
> +	/* skip the first / */
> +	pos = path + 1;
> +	while (1) {
> +		pos = strchr(pos, '/');
> +
> +		if (pos)
> +			*pos = 0;
> +		snprintf(fpath, PATH_MAX, "%s/%s/%s", prefix, path, prop);
> +		if (pos) {
> +			*pos = '/';
> +			pos++;
> +		}
> +
> +		out = openat(cg, fpath, O_RDWR);
> +		if (out < 0) {
> +			pr_perror("couldn't open cg prop at %s\n", fpath);
> +			return -1;
> +		}
> +
> +		ret = write(out, value, strlen(value));
> +		close(out);
> +
> +		if (ret < 0) {
> +			pr_perror("copying property %s to %s failed\n", prop, fpath);
> +			return -1;
> +		}
> +
> +		if (!pos)
> +			break;
> +	}
> +
> +	return 0;
> +}
> +
> +static int copy_special_cg_props(const char *controller, char *path)
> +{
>  	pr_info("copying special cg props for %s\n", controller);
>  
>  	if (strstr(controller, "cpuset")) {
>  		int i;
>  
>  		for (i = 0; special_cpuset_props[i]; i++) {
> -			char fpath[PATH_MAX], buf[1024];
> +			char buf[1024], prefix[PATH_MAX], missing_path[PATH_MAX];
>  			const char *prop = special_cpuset_props[i];
> -			int ret;
> -			FILE *f;
> -
> -			snprintf(fpath, PATH_MAX, "%s/%s", controller, prop);
> -			f = fopenat(cg, fpath, "r");
> -			if (!f)
> +			if (find_value(controller, path, prop, buf, prefix, missing_path) < 0)
>  				return -1;
>  
> -			ret = fscanf(f, "%1024s", buf);
> -			fclose(f);
> -
> -			if (ret <= 0) {
> -				continue;
> -			}
> -
> -			pr_info("copying %s for %s/%s\n", buf, controller, prop);
> -
> -			snprintf(fpath, PATH_MAX, "%s/%s/%s", controller, path, prop);
> -			f = fopenat(cg, fpath, "w");
> -			if (!f)
> +			if (copy_recursive(prefix, missing_path, prop, buf) < 0) {
> +				pr_err("copying prop %s failed\n", prop);
>  				return -1;
> -
> -			fprintf(f, "%s", buf);
> -			fclose(f);
> +			}
>  		}
>  	}
>  
> 



More information about the CRIU mailing list