]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
clone: don't ever mark the clone's rootfs as being the old, on disk
authorSerge Hallyn <serge.hallyn@ubuntu.com>
Fri, 28 Feb 2014 03:49:27 +0000 (21:49 -0600)
committerStéphane Graber <stgraber@ubuntu.com>
Mon, 3 Mar 2014 16:03:20 +0000 (11:03 -0500)
Otherwise an interrupted clone can lead to the original rootfs
being delete.

There is a period during lxcapi_clone during which we have written down
a temporary configuration file on disk, for the new container, using the
old rootfs. Interruption of clone doesn't allow us to do the cleanup we
do in error paths, so a subsequent lxc-destroy removes the old rootfs.

Fix this by doing the copy_storage as early as possible, and not
writing down the rootfs when we write down the temporary configuration
file.

(note - I tested this by putting a series of
'if (strcmp(newname, "u%d") == 0) exit(1)' inline to trigger
interruption between most blocks.  If someone has a good idea
for a generic way to regression-test this henceforth that'd be
great)

See https://bugs.launchpad.net/lxc/+bug/1285850

Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
Acked-by: Stéphane Graber <stgraber@ubuntu.com>
src/lxc/lxccontainer.c

index d9aa973f47b3c1a3c330ada7b9167f9f4ac298c2..c60f927177fd387b3b67c955d1708119efe66599 100644 (file)
@@ -2610,6 +2610,7 @@ static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *n
        char newpath[MAXPATHLEN];
        int ret, storage_copied = 0;
        const char *n, *l;
+       char *origroot = NULL;
        struct clone_update_data data;
        FILE *fout;
        pid_t pid;
@@ -2645,6 +2646,10 @@ static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *n
        }
 
        // copy the configuration, tweak it as needed,
+       if (c->lxc_conf->rootfs.path) {
+               origroot = c->lxc_conf->rootfs.path;
+               c->lxc_conf->rootfs.path = NULL;
+       }
        fout = fopen(newpath, "w");
        if (!fout) {
                SYSERROR("open %s", newpath);
@@ -2652,6 +2657,7 @@ static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *n
        }
        write_config(fout, c->lxc_conf);
        fclose(fout);
+       c->lxc_conf->rootfs.path = origroot;
 
        sprintf(newpath, "%s/%s/rootfs", l, n);
        if (mkdir(newpath, 0755) < 0) {
@@ -2671,6 +2677,12 @@ static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *n
                ERROR("clone: failed to create new container (%s %s)", n, l);
                goto out;
        }
+       c2->lxc_conf->rootfs.path = origroot;
+
+       // copy/snapshot rootfs's
+       ret = copy_storage(c, c2, bdevtype, flags, bdevdata, newsize);
+       if (ret < 0)
+               goto out;
 
        // update utsname
        if (!set_config_item_locked(c2, "lxc.utsname", newname)) {
@@ -2694,11 +2706,6 @@ static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *n
        if (!(flags & LXC_CLONE_KEEPMACADDR))
                network_new_hwaddrs(c2);
 
-       // copy/snapshot rootfs's
-       ret = copy_storage(c, c2, bdevtype, flags, bdevdata, newsize);
-       if (ret < 0)
-               goto out;
-
        // We've now successfully created c2's storage, so clear it out if we
        // fail after this
        storage_copied = 1;