From: Christian Brauner Date: Sun, 25 Apr 2021 07:59:42 +0000 (+0200) Subject: conf: stash lxc_storage into lxc_rootfs and bind to its lifetime X-Git-Tag: lxc-5.0.0~190^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4e86cad35be144d3b9e78c527186ab4d7b808e1f;p=thirdparty%2Flxc.git conf: stash lxc_storage into lxc_rootfs and bind to its lifetime Signed-off-by: Christian Brauner --- diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 3ca5cf447..71ea7cf95 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -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"); diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 05e4197cb..ef118794c 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -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; } } diff --git a/src/lxc/criu.c b/src/lxc/criu.c index c7e49b163..9da78e3f0 100644 --- a/src/lxc/criu.c +++ b/src/lxc/criu.c @@ -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; diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 5c85c86e7..34149675e 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -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; diff --git a/src/lxc/start.c b/src/lxc/start.c index c83c0f72e..070cae712 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -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; diff --git a/src/lxc/storage/rsync.c b/src/lxc/storage/rsync.c index b369f9c63..c02a3f95d 100644 --- a/src/lxc/storage/rsync.c +++ b/src/lxc/storage/rsync.c @@ -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; diff --git a/src/lxc/storage/storage.c b/src/lxc/storage/storage.c index 4a6de6118..061983a0a 100644 --- a/src/lxc/storage/storage.c +++ b/src/lxc/storage/storage.c @@ -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)