]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
conf: stash lxc_storage into lxc_rootfs and bind to its lifetime
authorChristian Brauner <christian.brauner@ubuntu.com>
Sun, 25 Apr 2021 07:59:42 +0000 (09:59 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Sun, 25 Apr 2021 11:55:49 +0000 (13:55 +0200)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/conf.c
src/lxc/conf.h
src/lxc/criu.c
src/lxc/lxccontainer.c
src/lxc/start.c
src/lxc/storage/rsync.c
src/lxc/storage/storage.c

index 3ca5cf44755f07d12073ec2884f1ead080399a2a..71ea7cf95c722d69a77414f747d9fb7c76ae425c 100644 (file)
@@ -483,6 +483,43 @@ int run_script(const char *name, const char *section, const char *script, ...)
        return run_buffer(buffer);
 }
 
+int lxc_storage_prepare(struct lxc_conf *conf)
+{
+       int ret;
+       struct lxc_rootfs *rootfs = &conf->rootfs;
+
+       if (!rootfs->path) {
+               ret = mount("", "/", NULL, MS_SLAVE | MS_REC, 0);
+               if (ret < 0)
+                       return log_error_errno(-1, errno, "Failed to recursively turn root mount tree into dependent mount");
+
+               rootfs->dfd_mnt = open_at(-EBADF, "/", PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_ABSOLUTE, 0);
+               if (rootfs->dfd_mnt < 0)
+                       return -errno;
+
+               return 0;
+       }
+
+       ret = access(rootfs->mount, F_OK);
+       if (ret != 0)
+               return log_error_errno(-1, errno, "Failed to access to \"%s\". Check it is present",
+                                      rootfs->mount);
+
+       rootfs->storage = storage_init(conf);
+       if (!rootfs->storage)
+               return log_error(-1, "Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\"",
+                                rootfs->path, rootfs->mount,
+                                rootfs->options ? rootfs->options : "(null)");
+
+       return 0;
+}
+
+void lxc_storage_put(struct lxc_conf *conf)
+{
+       storage_put(conf->rootfs.storage);
+       conf->rootfs.storage = NULL;
+}
+
 /* lxc_rootfs_prepare
  * if rootfs is a directory, then open ${rootfs}/.lxc-keep for writing for
  * the duration of the container run, to prevent the container from marking
@@ -490,12 +527,17 @@ int run_script(const char *name, const char *section, const char *script, ...)
  * no name pollution is happens.
  * don't unlink on NFS to avoid random named stale handles.
  */
-int lxc_rootfs_prepare(struct lxc_rootfs *rootfs, bool userns)
+int lxc_rootfs_prepare(struct lxc_conf *conf, bool userns)
 {
        __do_close int dfd_path = -EBADF, fd_pin = -EBADF, fd_userns = -EBADF;
        int ret;
        struct stat st;
        struct statfs stfs;
+       struct lxc_rootfs *rootfs = &conf->rootfs;
+
+       ret = lxc_storage_prepare(conf);
+       if (ret)
+               return syserror_set(-EINVAL, "Failed to prepare rootfs storage");
 
        if (!is_empty_string(rootfs->mnt_opts.userns_path)) {
                if (!rootfs->path)
@@ -1286,11 +1328,9 @@ static int lxc_fill_autodev(struct lxc_rootfs *rootfs)
        return 0;
 }
 
-static int lxc_mount_rootfs(struct lxc_conf *conf)
+static int lxc_mount_rootfs(struct lxc_rootfs *rootfs)
 {
        int ret;
-       struct lxc_storage *bdev;
-       struct lxc_rootfs *rootfs = &conf->rootfs;
 
        if (!rootfs->path) {
                ret = mount("", "/", NULL, MS_SLAVE | MS_REC, 0);
@@ -1309,14 +1349,7 @@ static int lxc_mount_rootfs(struct lxc_conf *conf)
                return log_error_errno(-1, errno, "Failed to access to \"%s\". Check it is present",
                                       rootfs->mount);
 
-       bdev = storage_init(conf);
-       if (!bdev)
-               return log_error(-1, "Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\"",
-                                rootfs->path, rootfs->mount,
-                                rootfs->options ? rootfs->options : "(null)");
-
-       ret = bdev->ops->mount(bdev);
-       storage_put(bdev);
+       ret = rootfs->storage->ops->mount(rootfs->storage);
        if (ret < 0)
                return log_error(-1, "Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\"",
                                 rootfs->path, rootfs->mount,
@@ -3361,7 +3394,7 @@ int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf, const char *name,
        if (ret < 0)
                return log_error(-1, "Failed to run pre-mount hooks");
 
-       ret = lxc_mount_rootfs(conf);
+       ret = lxc_mount_rootfs(&conf->rootfs);
        if (ret < 0)
                return log_error(-1, "Failed to setup rootfs for");
 
index 05e4197cbefbed0873d600b72995569808df5501..ef118794ca2234b5db6a1129776091a856326f29 100644 (file)
@@ -24,6 +24,7 @@
 #include "memory_utils.h"
 #include "ringbuf.h"
 #include "start.h"
+#include "storage/storage.h"
 #include "string_utils.h"
 #include "terminal.h"
 
@@ -232,6 +233,7 @@ struct lxc_rootfs {
        char *data;
        bool managed;
        struct lxc_mount_options mnt_opts;
+       struct lxc_storage *storage;
 };
 
 /*
@@ -500,7 +502,9 @@ extern thread_local struct lxc_conf *current_config;
 __hidden extern int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf, char *argv[]);
 __hidden extern struct lxc_conf *lxc_conf_init(void);
 __hidden extern void lxc_conf_free(struct lxc_conf *conf);
-__hidden extern int lxc_rootfs_prepare(struct lxc_rootfs *rootfs, bool userns);
+__hidden extern int lxc_storage_prepare(struct lxc_conf *conf);
+__hidden extern int lxc_rootfs_prepare(struct lxc_conf *conf, bool userns);
+__hidden extern void lxc_storage_put(struct lxc_conf *conf);
 __hidden extern int lxc_map_ids(struct lxc_list *idmap, pid_t pid);
 __hidden extern int lxc_create_tty(const char *name, struct lxc_conf *conf);
 __hidden extern void lxc_delete_tty(struct lxc_tty_info *ttys);
@@ -590,6 +594,8 @@ static inline void put_lxc_rootfs(struct lxc_rootfs *rootfs, bool unpin)
                close_prot_errno_disarm(rootfs->mnt_opts.userns_fd);
                if (unpin)
                        close_prot_errno_disarm(rootfs->fd_path_pin);
+               storage_put(rootfs->storage);
+               rootfs->storage = NULL;
        }
 }
 
index c7e49b1639580391e57ba68eb043e5436bf2ff6d..9da78e3f0784a1a0053d02145282eb87b82ed73f 100644 (file)
@@ -964,6 +964,10 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
                if (unshare(CLONE_NEWNS))
                        goto out_fini_handler;
 
+               ret = lxc_storage_prepare(c->lxc_conf);
+               if (ret)
+                       goto out_fini_handler;
+
                /* CRIU needs the lxc root bind mounted so that it is the root of some
                 * mount. */
                rootfs = &c->lxc_conf->rootfs;
index 5c85c86e7b35aa49fe136d226babf331938af030..34149675ed607d0405843427459d80c8f848f2a5 100644 (file)
@@ -1345,11 +1345,12 @@ static bool create_run_template(struct lxc_container *c, char *tpath,
                                _exit(EXIT_FAILURE);
                }
 
-               bdev = storage_init(c->lxc_conf);
-               if (!bdev) {
+               ret = lxc_storage_prepare(conf);
+               if (ret) {
                        ERROR("Failed to initialize storage");
                        _exit(EXIT_FAILURE);
                }
+               bdev = conf->rootfs.storage;
 
                euid = geteuid();
                if (euid == 0) {
@@ -3654,14 +3655,15 @@ static int clone_update_rootfs(struct clone_update_data *data)
        if (unshare(CLONE_NEWNS) < 0)
                return -1;
 
-       bdev = storage_init(c->lxc_conf);
-       if (!bdev)
+       ret = lxc_storage_prepare(conf);
+       if (ret)
                return -1;
+       bdev = conf->rootfs.storage;
 
        if (!strequal(bdev->type, "dir")) {
                if (unshare(CLONE_NEWNS) < 0) {
                        ERROR("error unsharing mounts");
-                       storage_put(bdev);
+                       lxc_storage_put(conf);
                        return -1;
                }
 
@@ -3669,7 +3671,7 @@ static int clone_update_rootfs(struct clone_update_data *data)
                        SYSERROR("Failed to recursively turn root mount tree into dependent mount. Continuing...");
 
                if (bdev->ops->mount(bdev) < 0) {
-                       storage_put(bdev);
+                       lxc_storage_put(conf);
                        return -1;
                }
        } else { /* TODO come up with a better way */
@@ -3696,14 +3698,14 @@ static int clone_update_rootfs(struct clone_update_data *data)
 
                if (run_lxc_hooks(c->name, "clone", conf, hookargs)) {
                        ERROR("Error executing clone hook for %s", c->name);
-                       storage_put(bdev);
+                       lxc_storage_put(conf);
                        return -1;
                }
        }
 
        if (!(flags & LXC_CLONE_KEEPNAME)) {
                ret = strnprintf(path, sizeof(path), "%s/etc/hostname", bdev->dest);
-               storage_put(bdev);
+               lxc_storage_put(conf);
 
                if (ret < 0)
                        return -1;
@@ -3724,7 +3726,7 @@ static int clone_update_rootfs(struct clone_update_data *data)
                if (fclose(fout) < 0)
                        return -1;
        } else {
-               storage_put(bdev);
+               lxc_storage_put(conf);
        }
 
        return 0;
@@ -3993,14 +3995,14 @@ static bool do_lxcapi_rename(struct lxc_container *c, const char *newname)
                return false;
        }
 
-       bdev = storage_init(c->lxc_conf);
-       if (!bdev) {
+       if (lxc_storage_prepare(c->lxc_conf)) {
                ERROR("Failed to find original backing store type");
                return false;
        }
+       bdev = c->lxc_conf->rootfs.storage;
 
        newc = lxcapi_clone(c, newname, c->config_path, LXC_CLONE_KEEPMACADDR, NULL, bdev->type, 0, NULL);
-       storage_put(bdev);
+       lxc_storage_put(c->lxc_conf);
        if (!newc) {
                lxc_container_put(newc);
                return false;
@@ -4376,11 +4378,11 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
                return false;
        }
 
-       bdev = storage_init(c->lxc_conf);
-       if (!bdev) {
+       if (lxc_storage_prepare(c->lxc_conf)) {
                ERROR("Failed to find original backing store type");
                return false;
        }
+       bdev = c->lxc_conf->rootfs.storage;
 
        /* For an overlay container the rootfs is considered immutable
         * and cannot be removed when restoring from a snapshot. We pass this
@@ -4394,7 +4396,7 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
                newname = c->name;
 
        if (!get_snappath_dir(c, clonelxcpath)) {
-               storage_put(bdev);
+               lxc_storage_put(c->lxc_conf);
                return false;
        }
        /* how should we lock this? */
@@ -4406,7 +4408,7 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
                if (snap)
                        lxc_container_put(snap);
 
-               storage_put(bdev);
+               lxc_storage_put(c->lxc_conf);
                return false;
        }
 
@@ -4414,7 +4416,7 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
                if (!container_destroy(c, bdev)) {
                        ERROR("Could not destroy existing container %s", newname);
                        lxc_container_put(snap);
-                       storage_put(bdev);
+                       lxc_storage_put(c->lxc_conf);
                        return false;
                }
        }
@@ -4427,7 +4429,7 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
 
        rest = lxcapi_clone(snap, newname, c->config_path, flags, bdev->type,
                            NULL, 0, NULL);
-       storage_put(bdev);
+       lxc_storage_put(c->lxc_conf);
        if (rest && lxcapi_is_defined(rest))
                b = true;
 
index c83c0f72e0acc2198c875794662f8acf0491f7a2..070cae712a9c94ddf0b7c1c7cde4eb6c777d964c 100644 (file)
@@ -2034,7 +2034,7 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops,
         * it readonly.
         * If the container is unprivileged then skip rootfs pinning.
         */
-       ret = lxc_rootfs_prepare(&conf->rootfs, !lxc_list_empty(&conf->id_map));
+       ret = lxc_rootfs_prepare(conf, !lxc_list_empty(&conf->id_map));
        if (ret) {
                ERROR("Failed to handle rootfs pinning for container \"%s\"", handler->name);
                ret = -1;
index b369f9c639e8997b22cb5acc35c201be170fa393..c02a3f95d75b0a0662c60d0fd6445f422f95dfe4 100644 (file)
@@ -86,12 +86,14 @@ int lxc_rsync(struct rsync_data *data)
                ERROR("Failed mounting \"%s\" on \"%s\"", orig->src, orig->dest);
                return -1;
        }
+       TRACE("Mounted \"%s\" on \"%s\"", orig->src, orig->dest);
 
        ret = new->ops->mount(new);
        if (ret < 0) {
                ERROR("Failed mounting \"%s\" onto \"%s\"", new->src, new->dest);
                return -1;
        }
+       TRACE("Mounted \"%s\" on \"%s\"", new->src, new->dest);
 
        if (!lxc_switch_uid_gid(0, 0))
                return -1;
index 4a6de6118616af875825ca9aa51dbbe8f541976a..061983a0a39f009d483c34699da091eef5625a63 100644 (file)
@@ -314,6 +314,15 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
        const char *oldpath = c->config_path;
        char cmd_output[PATH_MAX] = {0};
        struct rsync_data data = {0};
+       struct lxc_rootfs new_rootfs = {
+               .managed                = true,
+               .dfd_mnt                = -EBADF,
+               .dfd_dev                = -EBADF,
+               .dfd_host               = -EBADF,
+               .fd_path_pin            = -EBADF,
+               .dfd_idmapped           = -EBADF,
+               .mnt_opts.userns_fd     = -EBADF,
+       };
 
        if (!src) {
                ERROR("No rootfs specified");
@@ -329,11 +338,21 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
                return NULL;
        }
 
-       orig = storage_init(c->lxc_conf);
-       if (!orig) {
+       ret = lxc_storage_prepare(c->lxc_conf);
+       if (ret) {
                ERROR("Failed to detect storage driver for \"%s\"", oldname);
                return NULL;
        }
+       orig = c->lxc_conf->rootfs.storage;
+
+       if (c->lxc_conf->rootfs.dfd_idmapped >= 0) {
+               new_rootfs.dfd_idmapped = dup_cloexec(new_rootfs.dfd_idmapped);
+               if (new_rootfs.dfd_idmapped < 0) {
+                       SYSERROR("Failed to duplicate user namespace file descriptor");
+                       lxc_storage_put(c->lxc_conf);
+                       return NULL;
+               }
+       }
 
        if (!orig->dest) {
                size_t len;
@@ -404,6 +423,7 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
                goto on_error_put_orig;
        }
        TRACE("Initialized %s storage driver", new->type);
+       new->rootfs = &new_rootfs;
 
        /* create new paths */
        ret = new->ops->clone_paths(orig, new, oldname, cname, oldpath, lxcpath,
@@ -499,7 +519,7 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
        }
 
 on_success:
-       storage_put(orig);
+       lxc_storage_put(c->lxc_conf);
 
        return new;
 
@@ -507,7 +527,7 @@ on_error_put_new:
        storage_put(new);
 
 on_error_put_orig:
-       storage_put(orig);
+       lxc_storage_put(c->lxc_conf);
 
        return NULL;
 }
@@ -643,10 +663,12 @@ bool storage_is_dir(struct lxc_conf *conf)
 
 void storage_put(struct lxc_storage *bdev)
 {
-       free(bdev->mntopts);
-       free(bdev->src);
-       free(bdev->dest);
-       free(bdev);
+       if (bdev) {
+               free_disarm(bdev->mntopts);
+               free_disarm(bdev->src);
+               free_disarm(bdev->dest);
+               free_disarm(bdev);
+       }
 }
 
 bool rootfs_is_blockdev(struct lxc_conf *conf)