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
* 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)
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);
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,
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");
#include "memory_utils.h"
#include "ringbuf.h"
#include "start.h"
+#include "storage/storage.h"
#include "string_utils.h"
#include "terminal.h"
char *data;
bool managed;
struct lxc_mount_options mnt_opts;
+ struct lxc_storage *storage;
};
/*
__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);
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;
}
}
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;
_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) {
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;
}
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 */
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;
if (fclose(fout) < 0)
return -1;
} else {
- storage_put(bdev);
+ lxc_storage_put(conf);
}
return 0;
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;
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
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? */
if (snap)
lxc_container_put(snap);
- storage_put(bdev);
+ lxc_storage_put(c->lxc_conf);
return false;
}
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;
}
}
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;
* 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;
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;
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");
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;
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,
}
on_success:
- storage_put(orig);
+ lxc_storage_put(c->lxc_conf);
return new;
storage_put(new);
on_error_put_orig:
- storage_put(orig);
+ lxc_storage_put(c->lxc_conf);
return NULL;
}
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)