[lxc-devel] [lxc/master] conf: improve rootfs setup
brauner on Github
lxc-bot at linuxcontainers.org
Tue Jul 17 09:59:38 UTC 2018
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180717/c19182cc/attachment.bin>
-------------- next part --------------
From 6953bcb72e0f8bad30c651de4bd85f232bedacc9 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Tue, 17 Jul 2018 11:50:11 +0200
Subject: [PATCH] conf: improve rootfs setup
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
src/lxc/conf.c | 261 ++++++++++++++++++++++++++------------------------
src/lxc/conf.h | 13 ++-
src/lxc/confile.c | 26 ++++-
src/lxc/criu.c | 3 +-
src/lxc/start.c | 2 +-
src/lxc/storage/dir.c | 16 +++-
src/lxc/utils.c | 1 +
7 files changed, 187 insertions(+), 135 deletions(-)
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 33beb43d1..5283d0300 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -1104,84 +1104,6 @@ static int lxc_create_ttys(struct lxc_handler *handler)
return ret;
}
-static int setup_rootfs_pivot_root(const char *rootfs)
-{
- int ret;
- int newroot = -1, oldroot = -1;
-
- oldroot = open("/", O_DIRECTORY | O_RDONLY);
- if (oldroot < 0) {
- SYSERROR("Failed to open old root directory");
- return -1;
- }
-
- newroot = open(rootfs, O_DIRECTORY | O_RDONLY);
- if (newroot < 0) {
- SYSERROR("Failed to open new root directory");
- goto on_error;
- }
-
- /* change into new root fs */
- ret = fchdir(newroot);
- if (ret < 0) {
- SYSERROR("Failed to change to new rootfs \"%s\"", rootfs);
- goto on_error;
- }
-
- /* pivot_root into our new root fs */
- ret = pivot_root(".", ".");
- if (ret < 0) {
- SYSERROR("Failed to pivot_root()");
- goto on_error;
- }
-
- /* At this point the old-root is mounted on top of our new-root. To
- * unmounted it we must not be chdir'd into it, so escape back to
- * old-root.
- */
- ret = fchdir(oldroot);
- if (ret < 0) {
- SYSERROR("Failed to enter old root directory");
- goto on_error;
- }
-
- /* Make oldroot rslave to make sure our umounts don't propagate to the
- * host.
- */
- ret = mount("", ".", "", MS_SLAVE | MS_REC, NULL);
- if (ret < 0) {
- SYSERROR("Failed to make oldroot rslave");
- goto on_error;
- }
-
- ret = umount2(".", MNT_DETACH);
- if (ret < 0) {
- SYSERROR("Failed to detach old root directory");
- goto on_error;
- }
-
- ret = fchdir(newroot);
- if (ret < 0) {
- SYSERROR("Failed to re-enter new root directory");
- goto on_error;
- }
-
- close(oldroot);
- close(newroot);
-
- DEBUG("pivot_root(\"%s\") successful", rootfs);
-
- return 0;
-
-on_error:
- if (oldroot != -1)
- close(oldroot);
- if (newroot != -1)
- close(newroot);
-
- return -1;
-}
-
/* Just create a path for /dev under $lxcpath/$name and in rootfs If we hit an
* error, log it but don't fail yet.
*/
@@ -1365,17 +1287,16 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
return 0;
}
-static int lxc_setup_rootfs(struct lxc_conf *conf)
+static int lxc_mount_rootfs(struct lxc_conf *conf)
{
int ret;
struct lxc_storage *bdev;
- const struct lxc_rootfs *rootfs;
+ const struct lxc_rootfs *rootfs = &conf->rootfs;
- rootfs = &conf->rootfs;
if (!rootfs->path) {
ret = mount("", "/", NULL, MS_SLAVE | MS_REC, 0);
if (ret < 0) {
- SYSERROR("Failed to make / rslave");
+ SYSERROR("Failed to remount \"/\" MS_REC | MS_SLAVE");
return -1;
}
@@ -1413,33 +1334,36 @@ static int lxc_setup_rootfs(struct lxc_conf *conf)
return 0;
}
-int prepare_ramfs_root(char *root)
+int lxc_chroot(const struct lxc_rootfs *rootfs)
{
int i, ret;
char *p, *p2;
char buf[LXC_LINELEN], nroot[PATH_MAX];
FILE *f;
+ char *root = rootfs->mount;
- if (!realpath(root, nroot))
- return -1;
+ if (!realpath(root, nroot)) {
+ SYSERROR("Failed to resolve \"%s\"", root);
+ return -errno;
+ }
ret = chdir("/");
if (ret < 0)
- return -1;
+ return -errno;
/* We could use here MS_MOVE, but in userns this mount is locked and
* can't be moved.
*/
- ret = mount(root, "/", NULL, MS_REC | MS_BIND, NULL);
+ ret = mount(nroot, "/", NULL, MS_REC | MS_BIND, NULL);
if (ret < 0) {
- SYSERROR("Failed to move \"%s\" into \"/\"", root);
- return -1;
+ SYSERROR("Failed to mount \"%s\" onto \"/\" as MS_REC | MS_BIND", nroot);
+ return -errno;
}
ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL);
if (ret < 0) {
- SYSERROR("Failed to make \"/\" rprivate");
- return -1;
+ SYSERROR("Failed to remount \"/\"");
+ return -errno;
}
/* The following code cleans up inhereted mounts which are not required
@@ -1457,8 +1381,8 @@ int prepare_ramfs_root(char *root)
f = fopen("./proc/self/mountinfo", "r");
if (!f) {
- SYSERROR("Unable to open /proc/self/mountinfo");
- return -1;
+ SYSERROR("Failed to open \"/proc/self/mountinfo\"");
+ return -errno;
}
while (fgets(buf, LXC_LINELEN, f)) {
@@ -1498,53 +1422,143 @@ int prepare_ramfs_root(char *root)
/* It is weird, but chdir("..") moves us in a new root */
ret = chdir("..");
if (ret < 0) {
- SYSERROR("Unable to change working directory");
- return -1;
+ SYSERROR("Failed to chdir(\"..\")");
+ return -errno;
}
ret = chroot(".");
if (ret < 0) {
- SYSERROR("Unable to chroot");
- return -1;
+ SYSERROR("Failed to chroot(\".\")");
+ return -errno;
}
return 0;
}
-static int setup_pivot_root(const struct lxc_rootfs *rootfs)
+/* (The following explanation is copied verbatim from the kernel.)
+ *
+ * pivot_root Semantics:
+ * Moves the root file system of the current process to the directory put_old,
+ * makes new_root as the new root file system of the current process, and sets
+ * root/cwd of all processes which had them on the current root to new_root.
+ *
+ * Restrictions:
+ * The new_root and put_old must be directories, and must not be on the
+ * same file system as the current process root. The put_old must be
+ * underneath new_root, i.e. adding a non-zero number of /.. to the string
+ * pointed to by put_old must yield the same directory as new_root. No other
+ * file system may be mounted on put_old. After all, new_root is a mountpoint.
+ *
+ * Also, the current root cannot be on the 'rootfs' (initial ramfs) filesystem.
+ * See Documentation/filesystems/ramfs-rootfs-initramfs.txt for alternatives
+ * in this situation.
+ *
+ * Notes:
+ * - we don't move root/cwd if they are not at the root (reason: if something
+ * cared enough to change them, it's probably wrong to force them elsewhere)
+ * - it's okay to pick a root that isn't the root of a file system, e.g.
+ * /nfs/my_root where /nfs is the mount point. It must be a mountpoint,
+ * though, so you may need to say mount --bind /nfs/my_root /nfs/my_root
+ * first.
+ */
+static int lxc_pivot_root(const char *rootfs)
{
int ret;
+ int newroot = -1, oldroot = -1;
- if (!rootfs->path) {
- DEBUG("Container does not have a rootfs");
- return 0;
+ oldroot = open("/", O_DIRECTORY | O_RDONLY);
+ if (oldroot < 0) {
+ SYSERROR("Failed to open old root directory");
+ return -errno;
}
- if (detect_ramfs_rootfs()) {
- DEBUG("Detected that container is on ramfs");
+ newroot = open(rootfs, O_DIRECTORY | O_RDONLY);
+ if (newroot < 0) {
+ SYSERROR("Failed to open new root directory");
+ ret = -errno;
+ goto on_error;
+ }
- ret = prepare_ramfs_root(rootfs->mount);
- if (ret < 0) {
- ERROR("Failed to prepare minimal ramfs root");
- return -1;
- }
+ /* change into new root fs */
+ ret = fchdir(newroot);
+ if (ret < 0) {
+ SYSERROR("Failed to change to new rootfs \"%s\"", rootfs);
+ ret = -errno;
+ goto on_error;
+ }
- DEBUG("Prepared ramfs root for container");
- return 0;
+ /* pivot_root into our new root fs */
+ ret = pivot_root(".", ".");
+ if (ret < 0) {
+ SYSERROR("Failed to pivot_root()");
+ ret = -errno;
+ goto on_error;
}
- ret = setup_rootfs_pivot_root(rootfs->mount);
+ /* At this point the old-root is mounted on top of our new-root. To
+ * unmounted it we must not be chdir'd into it, so escape back to
+ * old-root.
+ */
+ ret = fchdir(oldroot);
if (ret < 0) {
- ERROR("Failed to pivot_root()");
- return -1;
+ SYSERROR("Failed to enter old root directory");
+ ret = -errno;
+ goto on_error;
}
- DEBUG("Finished pivot_root()");
- return 0;
+ /* Make oldroot rslave to make sure our umounts don't propagate to the
+ * host.
+ */
+ ret = mount("", ".", "", MS_SLAVE | MS_REC, NULL);
+ if (ret < 0) {
+ SYSERROR("Failed to make oldroot rslave");
+ ret = -errno;
+ goto on_error;
+ }
+
+ ret = umount2(".", MNT_DETACH);
+ if (ret < 0) {
+ SYSERROR("Failed to detach old root directory");
+ ret = -errno;
+ goto on_error;
+ }
+
+ ret = fchdir(newroot);
+ if (ret < 0) {
+ SYSERROR("Failed to re-enter new root directory");
+ ret = -errno;
+ goto on_error;
+ }
+
+ ret = 0;
+
+ TRACE("pivot_root(\"%s\") successful", rootfs);
+
+on_error:
+ if (oldroot != -1)
+ close(oldroot);
+ if (newroot != -1)
+ close(newroot);
+
+ return ret;
}
-static const struct id_map *find_mapped_nsid_entry(struct lxc_conf *conf, unsigned id,
- enum idtype idtype)
+static int lxc_setup_rootfs_switch_root(const struct lxc_rootfs *rootfs)
+{
+ if (!rootfs->path) {
+ DEBUG("Container does not have a rootfs");
+ return 0;
+ }
+
+ if (detect_ramfs_rootfs())
+ return lxc_chroot(rootfs);
+
+ return lxc_pivot_root(rootfs->mount);
+}
+
+static const struct id_map *find_mapped_nsid_entry(struct lxc_conf *conf,
+ unsigned id,
+ enum idtype idtype)
{
struct lxc_list *it;
struct id_map *map;
@@ -1903,7 +1917,7 @@ static void parse_propagationopt(char *opt, unsigned long *flags)
}
}
-static int parse_propagationopts(const char *mntopts, unsigned long *pflags)
+int parse_propagationopts(const char *mntopts, unsigned long *pflags)
{
char *p, *s;
char *saveptr = NULL;
@@ -3379,7 +3393,8 @@ static int lxc_execute_bind_init(struct lxc_handler *handler)
/* This does the work of remounting / if it is shared, calling the container
* pre-mount hooks, and mounting the rootfs.
*/
-int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath)
+int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf, const char *name,
+ const char *lxcpath)
{
int ret;
@@ -3392,7 +3407,7 @@ int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath
ret = mount(path, path, "rootfs", MS_BIND, NULL);
if (ret < 0) {
ERROR("Failed to bind mount container / onto itself");
- return -1;
+ return -errno;
}
TRACE("Bind mounted container / onto itself");
@@ -3407,7 +3422,7 @@ int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath
return -1;
}
- ret = lxc_setup_rootfs(conf);
+ ret = lxc_mount_rootfs(conf);
if (ret < 0) {
ERROR("Failed to setup rootfs for");
return -1;
@@ -3471,7 +3486,7 @@ int lxc_setup(struct lxc_handler *handler)
const char *lxcpath = handler->lxcpath, *name = handler->name;
struct lxc_conf *lxc_conf = handler->conf;
- ret = do_rootfs_setup(lxc_conf, name, lxcpath);
+ ret = lxc_setup_rootfs_prepare_root(lxc_conf, name, lxcpath);
if (ret < 0) {
ERROR("Failed to setup rootfs");
return -1;
@@ -3610,7 +3625,7 @@ int lxc_setup(struct lxc_handler *handler)
return -1;
}
- ret = setup_pivot_root(&lxc_conf->rootfs);
+ ret = lxc_setup_rootfs_switch_root(&lxc_conf->rootfs);
if (ret < 0) {
ERROR("Failed to pivot root into rootfs");
return -1;
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index f7a879c30..1c029feac 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -150,14 +150,18 @@ struct lxc_tty_info {
* optionals pivot_root, rootfs mount paths
* @path : the rootfs source (directory or device)
* @mount : where it is mounted
- * @options : mount options
* @bev_type : optional backing store type
+ * @options : mount options
+ * @mountflags : the portion of @options that are flags
+ * @data : the porition of @options that are not flags
*/
struct lxc_rootfs {
char *path;
char *mount;
- char *options;
char *bdev_type;
+ char *options;
+ unsigned long mountflags;
+ char *data;
};
/*
@@ -399,8 +403,8 @@ extern int lxc_clear_environment(struct lxc_conf *c);
extern int lxc_clear_limits(struct lxc_conf *c, const char *key);
extern int lxc_delete_autodev(struct lxc_handler *handler);
extern void lxc_clear_includes(struct lxc_conf *conf);
-extern int do_rootfs_setup(struct lxc_conf *conf, const char *name,
- const char *lxcpath);
+extern int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf,
+ const char *name, const char *lxcpath);
extern int lxc_setup(struct lxc_handler *handler);
extern int lxc_setup_parent(struct lxc_handler *handler);
extern int setup_resource_limits(struct lxc_list *limits, pid_t pid);
@@ -414,6 +418,7 @@ extern int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *),
void *data, const char *fn_name);
extern int parse_mntopts(const char *mntopts, unsigned long *mntflags,
char **mntdata);
+extern int parse_propagationopts(const char *mntopts, unsigned long *pflags);
extern void tmp_proc_unmount(struct lxc_conf *lxc_conf);
extern void remount_all_slave(void);
extern void suggest_default_idmap(void);
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 5a18d11bf..61a63f5dd 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -2073,7 +2073,27 @@ static int set_config_rootfs_mount(const char *key, const char *value,
static int set_config_rootfs_options(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data)
{
- return set_config_string_item(&lxc_conf->rootfs.options, value);
+ int ret;
+ unsigned long pflags = 0;
+ struct lxc_rootfs *rootfs = &lxc_conf->rootfs;
+
+ ret = set_config_string_item(&rootfs->options, value);
+ if (ret < 0)
+ return -EINVAL;
+
+ ret = parse_mntopts(value, &rootfs->mountflags, &rootfs->data);
+ if (ret < 0)
+ return -EINVAL;
+
+ ret = parse_propagationopts(value, &pflags);
+ if (ret < 0) {
+ free(rootfs->data);
+ return -EINVAL;
+ }
+
+ rootfs->mountflags |= pflags;
+
+ return 0;
}
static int set_config_uts_name(const char *key, const char *value,
@@ -3856,6 +3876,10 @@ static inline int clr_config_rootfs_options(const char *key, struct lxc_conf *c,
{
free(c->rootfs.options);
c->rootfs.options = NULL;
+
+ free(c->rootfs.data);
+ c->rootfs.data = NULL;
+
return 0;
}
diff --git a/src/lxc/criu.c b/src/lxc/criu.c
index c36421627..0feaeac07 100644
--- a/src/lxc/criu.c
+++ b/src/lxc/criu.c
@@ -1015,7 +1015,8 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
rootfs = &c->lxc_conf->rootfs;
if (rootfs_is_blockdev(c->lxc_conf)) {
- if (do_rootfs_setup(c->lxc_conf, c->name, c->config_path) < 0)
+ if (lxc_setup_rootfs_prepare_root(c->lxc_conf, c->name,
+ c->config_path) < 0)
goto out_fini_handler;
} else {
if (mkdir(rootfs->mount, 0755) < 0 && errno != EEXIST)
diff --git a/src/lxc/start.c b/src/lxc/start.c
index 180a37ab4..65a5e1eba 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -1882,7 +1882,7 @@ int __lxc_start(const char *name, struct lxc_handler *handler,
INFO("Unshared CLONE_NEWNS");
remount_all_slave();
- ret = do_rootfs_setup(conf, name, lxcpath);
+ ret = lxc_setup_rootfs_prepare_root(conf, name, lxcpath);
if (ret < 0) {
ERROR("Error setting up rootfs mount as root before spawn");
goto out_fini_nonet;
diff --git a/src/lxc/storage/dir.c b/src/lxc/storage/dir.c
index bfd3827de..2414f533e 100644
--- a/src/lxc/storage/dir.c
+++ b/src/lxc/storage/dir.c
@@ -157,7 +157,7 @@ bool dir_detect(const char *path)
int dir_mount(struct lxc_storage *bdev)
{
int ret;
- unsigned long mflags, mntflags;
+ unsigned long mflags = 0, mntflags = 0, pflags = 0;
char *mntdata;
const char *src;
@@ -171,17 +171,23 @@ int dir_mount(struct lxc_storage *bdev)
if (ret < 0) {
ERROR("Failed to parse mount options \"%s\"", bdev->mntopts);
free(mntdata);
- return -22;
+ return -EINVAL;
+ }
+
+ ret = parse_propagationopts(bdev->mntopts, &pflags);
+ if (ret < 0) {
+ ERROR("Failed to parse propagation options \"%s\"", bdev->mntopts);
+ free(mntdata);
+ return -EINVAL;
}
src = lxc_storage_get_path(bdev->src, bdev->type);
- ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags,
- mntdata);
+ ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags | pflags, mntdata);
if ((0 == ret) && (mntflags & MS_RDONLY)) {
DEBUG("Remounting \"%s\" on \"%s\" readonly",
src ? src : "(none)", bdev->dest ? bdev->dest : "(none)");
- mflags = add_required_remount_flags(src, bdev->dest, MS_BIND | MS_REC | mntflags | MS_REMOUNT);
+ mflags = add_required_remount_flags(src, bdev->dest, MS_BIND | MS_REC | mntflags | pflags | MS_REMOUNT);
ret = mount(src, bdev->dest, "bind", mflags, mntdata);
}
diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index 6bb05df00..af18791a0 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -1324,6 +1324,7 @@ bool detect_ramfs_rootfs(void)
if (p && strncmp(p, "- rootfs rootfs ", 16) == 0) {
free(line);
fclose(f);
+ INFO("Rootfs is located on ramfs");
return true;
}
}
More information about the lxc-devel
mailing list