[CRIU] [PATCH] restore: copy special cpuset props recursively
Tycho Andersen
tycho.andersen at canonical.com
Wed Oct 1 11:48:00 PDT 2014
Hi Pavel,
On Wed, Oct 01, 2014 at 04:33:29PM +0400, Pavel Emelyanov wrote:
> 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?
I played around with this just now, but it turns out we still need
something like the code above, since we do a mkdir -p of the initial
path in the images. It could exist and have multiple levels, so we
still need to walk backwards to find the first one with a value
defined, and then walk forwards to define it. I think it is probably
best to merge this as-is, the other way seems more complicated to me.
Tycho
> > 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