]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
overlay: correctly restore from snapshot
authorChristian Brauner <christian.brauner@ubuntu.com>
Tue, 1 Aug 2017 17:54:24 +0000 (19:54 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Tue, 1 Aug 2017 18:24:03 +0000 (20:24 +0200)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/lxccontainer.c
src/lxc/storage/btrfs.c
src/lxc/storage/lvm.c
src/lxc/storage/overlay.c
src/lxc/storage/rsync.c
src/lxc/storage/rsync.h
src/lxc/storage/storage.c
src/lxc/storage/storage.h
src/lxc/storage/zfs.c

index b81f119160c94392bc07d3e80e7d16261ed3fd03..3639d6f2800a3e8e69c97fe7c3a267438849c251 100644 (file)
@@ -106,7 +106,8 @@ static bool do_lxcapi_destroy(struct lxc_container *c);
 static const char *lxcapi_get_config_path(struct lxc_container *c);
 #define do_lxcapi_get_config_path(c) lxcapi_get_config_path(c)
 static bool do_lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v);
-static bool container_destroy(struct lxc_container *c);
+static bool container_destroy(struct lxc_container *c,
+                             struct lxc_storage *storage);
 static bool get_snappath_dir(struct lxc_container *c, char *snappath);
 static bool lxcapi_snapshot_destroy_all(struct lxc_container *c);
 static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file);
@@ -1742,7 +1743,7 @@ out_unlock:
                remove_partial(c, partial_fd);
 out:
        if (!ret)
-               container_destroy(c);
+               container_destroy(c, NULL);
 free_tpath:
        free(tpath);
        return ret;
@@ -2580,11 +2581,21 @@ static int lxc_rmdir_onedev_wrapper(void *data)
        return lxc_rmdir_onedev(arg, "snaps");
 }
 
-static bool container_destroy(struct lxc_container *c)
+static int lxc_unlink_exec_wrapper(void *data)
 {
+       char *arg = data;
+       return unlink(arg);
+}
+
+static bool container_destroy(struct lxc_container *c,
+                             struct lxc_storage *storage)
+{
+       const char *p1;
+       size_t len;
+       struct lxc_conf *conf;
+       char *path = NULL;
        bool bret = false;
        int ret = 0;
-       struct lxc_conf *conf;
 
        if (!c || !do_lxcapi_is_defined(c))
                return false;
@@ -2601,28 +2612,27 @@ static bool container_destroy(struct lxc_container *c)
 
        if (conf && !lxc_list_empty(&conf->hooks[LXCHOOK_DESTROY])) {
                /* Start of environment variable setup for hooks */
-               if (c->name && setenv("LXC_NAME", c->name, 1)) {
-                       SYSERROR("failed to set environment variable for container name");
-               }
-               if (conf->rcfile && setenv("LXC_CONFIG_FILE", conf->rcfile, 1)) {
-                       SYSERROR("failed to set environment variable for config path");
-               }
-               if (conf->rootfs.mount && setenv("LXC_ROOTFS_MOUNT", conf->rootfs.mount, 1)) {
-                       SYSERROR("failed to set environment variable for rootfs mount");
-               }
-               if (conf->rootfs.path && setenv("LXC_ROOTFS_PATH", conf->rootfs.path, 1)) {
-                       SYSERROR("failed to set environment variable for rootfs mount");
-               }
-               if (conf->console.path && setenv("LXC_CONSOLE", conf->console.path, 1)) {
-                       SYSERROR("failed to set environment variable for console path");
-               }
-               if (conf->console.log_path && setenv("LXC_CONSOLE_LOGPATH", conf->console.log_path, 1)) {
-                       SYSERROR("failed to set environment variable for console log");
-               }
+               if (c->name && setenv("LXC_NAME", c->name, 1))
+                       SYSERROR("Failed to set environment variable for container name");
+
+               if (conf->rcfile && setenv("LXC_CONFIG_FILE", conf->rcfile, 1))
+                       SYSERROR("Failed to set environment variable for config path");
+
+               if (conf->rootfs.mount && setenv("LXC_ROOTFS_MOUNT", conf->rootfs.mount, 1))
+                       SYSERROR("Failed to set environment variable for rootfs mount");
+
+               if (conf->rootfs.path && setenv("LXC_ROOTFS_PATH", conf->rootfs.path, 1))
+                       SYSERROR("Failed to set environment variable for rootfs mount");
+
+               if (conf->console.path && setenv("LXC_CONSOLE", conf->console.path, 1))
+                       SYSERROR("Failed to set environment variable for console path");
+
+               if (conf->console.log_path && setenv("LXC_CONSOLE_LOGPATH", conf->console.log_path, 1))
+                       SYSERROR("Failed to set environment variable for console log");
                /* End of environment variable setup for hooks */
 
                if (run_lxc_hooks(c->name, "destroy", conf, c->get_config_path(c), NULL)) {
-                       ERROR("Error executing clone hook for %s", c->name);
+                       ERROR("Failed to execute clone hook for \"%s\"", c->name);
                        goto out;
                }
        }
@@ -2645,23 +2655,72 @@ static bool container_destroy(struct lxc_container *c)
 
        mod_all_rdeps(c, false);
 
-       const char *p1 = do_lxcapi_get_config_path(c);
-       char *path = alloca(strlen(p1) + strlen(c->name) + 2);
-       sprintf(path, "%s/%s", p1, c->name);
+       p1 = do_lxcapi_get_config_path(c);
+       /* strlen(p1)
+        * +
+        * /
+        * +
+        * strlen(c->name)
+        * +
+        * /
+        * +
+        * strlen("config") = 6
+        * +
+        * \0
+        */
+       len = strlen(p1) + 1 + strlen(c->name) + 1 + 6 + 1;
+       path = malloc(len);
+       if (!path) {
+               ERROR("Failed to allocate memory");
+               goto out;
+       }
+
+       /* For an overlay container the rootfs is considered immutable and
+        * cannot be removed when restoring from a snapshot.
+        */
+       if (storage && (!strcmp(storage->type, "overlay") ||
+                       !strcmp(storage->type, "overlayfs")) &&
+           (storage->flags & LXC_STORAGE_INTERNAL_OVERLAY_RESTORE)) {
+               ret = snprintf(path, len, "%s/%s/config", p1, c->name);
+               if (ret < 0 || (size_t)ret >= len)
+                       goto out;
+
+               if (am_unpriv())
+                       ret = userns_exec_1(conf, lxc_unlink_exec_wrapper, path,
+                                           "lxc_unlink_exec_wrapper");
+               else
+                       ret = unlink(path);
+               if (ret < 0) {
+                       SYSERROR("Failed to destroy config file \"%s\" for \"%s\"",
+                                path, c->name);
+                       goto out;
+               }
+               INFO("Destroyed config file \"%s\" for \"%s\"", path, c->name);
+
+               bret = true;
+               goto out;
+       }
+
+       ret = snprintf(path, len, "%s/%s", p1, c->name);
+       if (ret < 0 || (size_t)ret >= len)
+               goto out;
        if (am_unpriv())
                ret = userns_exec_1(conf, lxc_rmdir_onedev_wrapper, path,
                                    "lxc_rmdir_onedev_wrapper");
        else
                ret = lxc_rmdir_onedev(path, "snaps");
        if (ret < 0) {
-               ERROR("Error destroying container directory for %s", c->name);
+               ERROR("Failed to destroy directory \"%s\" for \"%s\"", path,
+                     c->name);
                goto out;
        }
-       INFO("Destroyed directory for %s", c->name);
+       INFO("Destroyed directory \"%s\" for \"%s\"", path, c->name);
 
        bret = true;
 
 out:
+       if (path)
+               free(path);
        container_disk_unlock(c);
        return bret;
 }
@@ -2680,7 +2739,7 @@ static bool do_lxcapi_destroy(struct lxc_container *c)
                return false;
        }
 
-       return container_destroy(c);
+       return container_destroy(c, NULL);
 }
 
 WRAP_API(bool, lxcapi_destroy)
@@ -3314,14 +3373,15 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
                const char *bdevtype, const char *bdevdata, uint64_t newsize,
                char **hookargs)
 {
-       struct lxc_container *c2 = NULL;
        char newpath[MAXPATHLEN];
-       int ret, storage_copied = 0;
-       char *origroot = NULL, *saved_unexp_conf = NULL;
+       int ret;
        struct clone_update_data data;
        size_t saved_unexp_len;
        FILE *fout;
        pid_t pid;
+       int storage_copied = 0;
+       char *origroot = NULL, *saved_unexp_conf = NULL;
+       struct lxc_container *c2 = NULL;
 
        if (!c || !do_lxcapi_is_defined(c))
                return NULL;
@@ -3344,6 +3404,7 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
                SYSERROR("clone: failed making config pathname");
                goto out;
        }
+
        if (file_exists(newpath)) {
                ERROR("error: clone: %s exists", newpath);
                goto out;
@@ -3394,9 +3455,18 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
                SYSERROR("clone: failed making rootfs pathname");
                goto out;
        }
-       if (mkdir(newpath, 0755) < 0) {
-               SYSERROR("error creating %s", newpath);
-               goto out;
+
+       ret = mkdir(newpath, 0755);
+       if (ret < 0) {
+               /* For an overlay container the rootfs is considered immutable
+                * and will not have been removed when restoring from a
+                * snapshot.
+                */
+               if (errno != ENOENT &&
+                   !(flags & LXC_STORAGE_INTERNAL_OVERLAY_RESTORE)) {
+                       SYSERROR("Failed to create directory \"%s\"", newpath);
+                       goto out;
+               }
        }
 
        if (am_unpriv()) {
@@ -3539,7 +3609,7 @@ static bool do_lxcapi_rename(struct lxc_container *c, const char *newname)
        if (newc && lxcapi_is_defined(newc))
                lxc_container_put(newc);
 
-       if (!container_destroy(c)) {
+       if (!container_destroy(c, NULL)) {
                ERROR("Could not destroy existing container %s", c->name);
                return false;
        }
@@ -3873,12 +3943,21 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
                return false;
        }
 
-       bdev = storage_init(c->lxc_conf, c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL);
+       bdev = storage_init(c->lxc_conf, c->lxc_conf->rootfs.path,
+                           c->lxc_conf->rootfs.mount, NULL);
        if (!bdev) {
                ERROR("Failed to find original backing store type");
                return false;
        }
 
+       /* For an overlay container the rootfs is considered immutable
+        * and cannot be removed when restoring from a snapshot. We pass this
+        * internal flag along to communicate this to various parts of the
+        * codebase.
+        */
+       if (!strcmp(bdev->type, "overlay") || !strcmp(bdev->type, "overlayfs"))
+               bdev->flags |= LXC_STORAGE_INTERNAL_OVERLAY_RESTORE;
+
        if (!newname)
                newname = c->name;
 
@@ -3891,13 +3970,14 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
        snap = lxc_container_new(snapname, clonelxcpath);
        if (!snap || !lxcapi_is_defined(snap)) {
                ERROR("Could not open snapshot %s", snapname);
-               if (snap) lxc_container_put(snap);
+               if (snap)
+                       lxc_container_put(snap);
                storage_put(bdev);
                return false;
        }
 
-       if (strcmp(c->name, newname) == 0) {
-               if (!container_destroy(c)) {
+       if (!strcmp(c->name, newname)) {
+               if (!container_destroy(c, bdev)) {
                        ERROR("Could not destroy existing container %s", newname);
                        lxc_container_put(snap);
                        storage_put(bdev);
@@ -3907,6 +3987,9 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
 
        if (strcmp(bdev->type, "dir") != 0 && strcmp(bdev->type, "loop") != 0)
                flags = LXC_CLONE_SNAPSHOT | LXC_CLONE_MAYBE_SNAPSHOT;
+
+       if (!strcmp(bdev->type, "overlay") || !strcmp(bdev->type, "overlayfs"))
+               flags |= LXC_STORAGE_INTERNAL_OVERLAY_RESTORE;
        rest = lxcapi_clone(snap, newname, c->config_path, flags,
                        bdev->type, NULL, 0, NULL);
        storage_put(bdev);
@@ -3914,6 +3997,7 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
                b = true;
        if (rest)
                lxc_container_put(rest);
+
        lxc_container_put(snap);
        return b;
 }
@@ -4414,7 +4498,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
 
        if (ongoing_create(c) == 2) {
                ERROR("Error: %s creation was not completed", c->name);
-               container_destroy(c);
+               container_destroy(c, NULL);
                lxcapi_clear_config(c);
        }
        c->daemonize = true;
index 18755aa019045fe4285b8ec0fedb4ee4fe300884..3057cf546b1eb4e35f3fc26eebd9895a726650ec 100644 (file)
@@ -438,8 +438,8 @@ bool btrfs_create_clone(struct lxc_conf *conf, struct lxc_storage *orig,
        data.orig = orig;
        data.new = new;
        if (am_unpriv()) {
-               ret = userns_exec_1(conf, lxc_rsync_exec_wrapper, &data,
-                                   "lxc_rsync_exec_wrapper");
+               ret = userns_exec_1(conf, lxc_storage_rsync_exec_wrapper, &data,
+                                   "lxc_storage_rsync_exec_wrapper");
                if (ret < 0) {
                        ERROR("Failed to rsync from \"%s\" into \"%s\"",
                              orig->dest, new->dest);
@@ -450,7 +450,7 @@ bool btrfs_create_clone(struct lxc_conf *conf, struct lxc_storage *orig,
        }
 
        ret = run_command(cmd_output, sizeof(cmd_output),
-                       lxc_rsync_exec_wrapper, (void *)&data);
+                       lxc_storage_rsync_exec_wrapper, (void *)&data);
        if (ret < 0) {
                ERROR("Failed to rsync from \"%s\" into \"%s\": %s", orig->dest,
                      new->dest, cmd_output);
index fc3a2c48572244e70e0f2e1df11fe7efc76c66cf..6ceab1dea934bdfaee397dfb1bbebda8d941f58c 100644 (file)
@@ -507,7 +507,7 @@ bool lvm_create_clone(struct lxc_conf *conf, struct lxc_storage *orig,
        data.orig = orig;
        data.new = new;
        ret = run_command(cmd_output, sizeof(cmd_output),
-                         lxc_rsync_exec_wrapper, (void *)&data);
+                         lxc_storage_rsync_exec_wrapper, (void *)&data);
        if (ret < 0) {
                ERROR("Failed to rsync from \"%s\" to \"%s\"", orig->dest,
                      new->dest);
index 1753dc1b020d5e5676805f379a0cbdd5a8f910d3..e63a6ba563d0f1090833a77b27a50b0e6ed68111 100644 (file)
@@ -43,7 +43,7 @@ static char *ovl_name;
 static char *ovl_version[] = {"overlay", "overlayfs"};
 
 static char *ovl_detect_name(void);
-static int ovl_do_rsync(struct lxc_storage *orig, struct lxc_storage *new,
+static int ovl_do_rsync(const char *src, const char *dest,
                        struct lxc_conf *conf);
 static int ovl_remount_on_enodev(const char *lower, const char *target,
                                 const char *name, unsigned long mountflags,
@@ -292,14 +292,16 @@ int ovl_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, const char
                        return -ENOMEM;
                }
                ret = snprintf(new->src, len, "overlay:%s:%s", nsrc, ndelta);
-               free(osrc);
-               free(ndelta);
                if (ret < 0 || (size_t)ret >= len) {
                        ERROR("Failed to create string");
+                       free(osrc);
+                       free(ndelta);
                        return -1;
                }
 
-               ret = ovl_do_rsync(orig, new, conf);
+               ret = ovl_do_rsync(odelta, ndelta, conf);
+               free(osrc);
+               free(ndelta);
                if (ret < 0)
                        return -1;
 
@@ -462,6 +464,12 @@ int ovl_destroy(struct lxc_storage *orig)
        if (!ovl && strncmp(upper, "overlayfs:", 10))
                return -22;
 
+       /* For an overlay container the rootfs is considered immutable
+        * and cannot be removed when restoring from a snapshot.
+        */
+       if (orig->flags & LXC_STORAGE_INTERNAL_OVERLAY_RESTORE)
+               return 0;
+
        if (ovl)
                upper += 8;
        else
@@ -953,28 +961,25 @@ static char *ovl_detect_name(void)
        return v;
 }
 
-static int ovl_do_rsync(struct lxc_storage *orig, struct lxc_storage *new,
+static int ovl_do_rsync(const char *src, const char *dest,
                        struct lxc_conf *conf)
 {
        int ret = -1;
-       struct rsync_data rdata = {0, 0};
+       struct rsync_data_char rdata = {0};
        char cmd_output[MAXPATHLEN] = {0};
 
-       rdata.orig = orig;
-       rdata.new = new;
-       if (am_unpriv()) {
+       rdata.src = (char *)src;
+       rdata.dest = (char *)dest;
+       if (am_unpriv())
                ret = userns_exec_1(conf, lxc_rsync_exec_wrapper, &rdata,
                                    "lxc_rsync_exec_wrapper");
-               if (ret < 0)
-                       ERROR("Failed to rsync from \"%s\" into \"%s\"",
-                             orig->dest, new->dest);
-       } else {
+       else
                ret = run_command(cmd_output, sizeof(cmd_output),
                                  lxc_rsync_exec_wrapper, (void *)&rdata);
-               if (ret < 0)
-                       ERROR("Failed to rsync from \"%s\" into \"%s\": %s",
-                             orig->dest, new->dest, cmd_output);
-       }
+       if (ret < 0)
+               ERROR("Failed to rsync from \"%s\" into \"%s\"%s%s", src, dest,
+                     cmd_output[0] != '\0' ? ": " : "",
+                     cmd_output[0] != '\0' ? cmd_output : "");
 
        return ret;
 }
index e50f4152b4c73be0615fdbc58bdb9dccc8700e9d..55c9504e797f4ba8f47700215df4053ff0845a05 100644 (file)
 
 lxc_log_define(rsync, lxc);
 
-int lxc_rsync_exec_wrapper(void *data)
+int lxc_storage_rsync_exec_wrapper(void *data)
 {
        struct rsync_data *arg = data;
        return lxc_rsync(arg);
 }
 
+int lxc_rsync_exec_wrapper(void *data)
+{
+       int ret;
+       struct rsync_data_char *args = data;
+
+       ret = lxc_switch_uid_gid(0, 0);
+       if (ret < 0)
+               return -1;
+
+       ret = lxc_setgroups(0, NULL);
+       if (ret < 0)
+               return -1;
+
+       return lxc_rsync_exec(args->src, args->dest);
+}
+
 int lxc_rsync_exec(const char *src, const char *dest)
 {
        int ret;
@@ -70,8 +86,8 @@ int lxc_rsync_exec(const char *src, const char *dest)
 int lxc_rsync(struct rsync_data *data)
 {
        int ret;
-       struct lxc_storage *orig = data->orig, *new = data->new;
        char *dest, *src;
+       struct lxc_storage *orig = data->orig, *new = data->new;
 
        ret = unshare(CLONE_NEWNS);
        if (ret < 0) {
@@ -101,6 +117,7 @@ int lxc_rsync(struct rsync_data *data)
        ret = lxc_switch_uid_gid(0, 0);
        if (ret < 0)
                return -1;
+
        ret = lxc_setgroups(0, NULL);
        if (ret < 0)
                return -1;
index d8581fe400baa9b070467fd0166cf4af72287b43..9984bc98be14980d5a9bee295cc102762a8dd30e 100644 (file)
@@ -39,6 +39,7 @@ struct rsync_data_char {
 
 /* new helpers */
 extern int lxc_rsync_exec_wrapper(void *data);
+extern int lxc_storage_rsync_exec_wrapper(void *data);
 extern int lxc_rsync_exec(const char *src, const char *dest);
 extern int lxc_rsync(struct rsync_data *data);
 
index 468563b8ceebd8ec6976b5ba54c767deb4a20a9c..fee3d8df157375053708d49d388dd373c3b88352 100644 (file)
@@ -502,11 +502,11 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
        data.orig = orig;
        data.new = new;
        if (am_unpriv())
-               ret = userns_exec_1(c->lxc_conf, lxc_rsync_exec_wrapper, &data,
-                                   "lxc_rsync_exec_wrapper");
+               ret = userns_exec_1(c->lxc_conf, lxc_storage_rsync_exec_wrapper,
+                                   &data, "lxc_storage_rsync_exec_wrapper");
        else
                ret = run_command(cmd_output, sizeof(cmd_output),
-                                 lxc_rsync_exec_wrapper, (void *)&data);
+                                 lxc_storage_rsync_exec_wrapper, (void *)&data);
        if (ret < 0) {
                ERROR("Failed to rsync from \"%s\" into \"%s\"%s%s", orig->dest,
                      new->dest,
@@ -598,6 +598,8 @@ struct lxc_storage *storage_init(struct lxc_conf *conf, const char *src,
        struct lxc_storage *bdev;
        const struct lxc_storage_type *q;
 
+       BUILD_BUG_ON(LXC_STORAGE_INTERNAL_OVERLAY_RESTORE <= LXC_CLONE_MAXFLAGS);
+
        if (!src)
                src = conf->rootfs.path;
 
index 735886cd2b5ce425a514c31e3ce99f54239226f2..082b59e05c8062fef13998d4ff5a1ad133fc07b1 100644 (file)
@@ -57,6 +57,8 @@
 #define DEFAULT_FS_SIZE 1073741824
 #define DEFAULT_FSTYPE "ext3"
 
+#define LXC_STORAGE_INTERNAL_OVERLAY_RESTORE  (1 << 6)
+
 struct lxc_storage;
 
 struct lxc_storage_ops {
@@ -97,6 +99,7 @@ struct lxc_storage {
        int lofd;
        /* index for the connected nbd device. */
        int nbd_idx;
+       int flags;
 };
 
 extern bool storage_is_dir(struct lxc_conf *conf, const char *path);
index a9f560fc3d17a9b1544e57b3520579c59e2399d2..1198fd52b04cd127d3291973e5bf4a2cb4121d99 100644 (file)
@@ -325,7 +325,7 @@ bool zfs_copy(struct lxc_conf *conf, struct lxc_storage *orig,
        data.orig = orig;
        data.new = new;
        ret = run_command(cmd_output, sizeof(cmd_output),
-                         lxc_rsync_exec_wrapper, (void *)&data);
+                         lxc_storage_rsync_exec_wrapper, (void *)&data);
        if (ret < 0) {
                ERROR("Failed to rsync from \"%s\" into \"%s\": %s", orig->dest,
                      new->dest, cmd_output);