From 8d2efe40a32700eaec6a8f3057b3b9bb16721b3d Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Thu, 27 Feb 2014 21:49:27 -0600 Subject: [PATCH] clone: don't ever mark the clone's rootfs as being the old, on disk MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Acked-by: Stéphane Graber --- src/lxc/lxccontainer.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index d9aa973f4..c60f92717 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -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; -- 2.39.5