[lxc-devel] [PATCH v3] Make overlayfs mounts work directly
Serge Hallyn
serge.hallyn at ubuntu.com
Mon Oct 5 13:45:53 UTC 2015
Quoting Christian Brauner (christianvanbrauner at gmail.com):
> When users wanted to mount overlay directories with lxc.mount.entry they had to
> create upperdirs and workdirs beforehand in order to mount them. To create it
> for them we add the functions mount_entry_create_overlay_dirs() and
> mount_entry_create_aufs_dirs() which do this for them. User can now simply
> specify e.g.:
>
> lxc.mount.entry = /lower merged overlay lowerdir=/lower,upper=/upper,workdir=/workdir,create=dir
>
> and /upper and /workdir will be created for them. /upper and /workdir need to
> be absolute paths to directories which are created under the containerdir (e.g.
> $lxcpath/container/). Relative mountpoints and mountpoints within the
> container's rootfs and outside the containerdir are ignored. (The latter
> *might* change in the future should it be considered safe/useful.)
>
> Specifying
>
> lxc.mount.entry = /lower merged overlay lowerdir=/lower:/lower2,create=dir
>
> will lead to a read-only overlay mount in accordance with the
> kernel-documentation.
>
> Specifying
>
> lxc.mount.entry = /lower merged overlay lowerdir=/lower,create=dir
>
> will fail when no upperdir and workdir options are given.
>
> Signed-off-by: Christian Brauner <christianvanbrauner at gmail.com>
> ---
> src/lxc/conf.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 141 insertions(+), 12 deletions(-)
>
> diff --git a/src/lxc/conf.c b/src/lxc/conf.c
> index bb4c19f..bb415ba 100644
> --- a/src/lxc/conf.c
> +++ b/src/lxc/conf.c
> @@ -1813,13 +1813,142 @@ static void cull_mntent_opt(struct mntent *mntent)
> }
> }
>
> +static int mount_entry_create_overlay_dirs(const struct mntent *mntent,
> + const struct lxc_rootfs *rootfs)
> +{
> + char *containerdir = NULL;
> + char *del = NULL;
> + char *upperdir = NULL;
> + char *workdir = NULL;
> + char **opts = NULL;
> + size_t arrlen = 0;
> + size_t dirlen = 0;
> + size_t i;
> + size_t len = 0;
> + size_t rootfslen = 0;
> +
> + opts = lxc_string_split(mntent->mnt_opts, ',');
> + if (opts)
> + arrlen = lxc_array_len((void **)opts);
> + else
> + return -1;
> +
> + for (i = 0; i < arrlen; i++) {
> + if (strstr(opts[i], "upperdir=") && (strlen(opts[i]) > (len = strlen("upperdir="))))
> + upperdir = opts[i] + len;
> + else if (strstr(opts[i], "workdir=") && (strlen(opts[i]) > (len = strlen("workdir="))))
> + workdir = opts[i] + len;
> + }
> +
> + containerdir = strdup(rootfs->path);
> + if (!containerdir) {
> + lxc_free_array((void **)opts, free);
> + return -1;
> + }
> +
> + if ((del = strstr(containerdir, "/rootfs"))) {
> + memmove(del, del + 7, strlen(del) - 7 + 1);
if rootfs->path happens to be /a/b/c/rootfs/d/e, you'll end up
making containerpath = /a/b/c/d/e right? Is that what you want, or
do you just want to *del = 0; ?
> + }
> +
> + dirlen = strlen(containerdir);
> + rootfslen = strlen(rootfs->path);
> +
> + /* We neither allow users to create upperdirs and workdirs outside the
> + * containerdir nor inside the rootfs. The latter might be debatable. */
> + if (upperdir)
> + if ((strncmp(upperdir, containerdir, dirlen) == 0) && (strncmp(upperdir, rootfs->path, rootfslen) != 0))
> + if (mkdir_p(upperdir, 0755) < 0) {
> + WARN("Failed to create upperdir");
> + }
> +
> +
> + if (workdir)
> + if ((strncmp(workdir, containerdir, dirlen) == 0) && (strncmp(workdir, rootfs->path, rootfslen) != 0))
> + if (mkdir_p(workdir, 0755) < 0) {
> + WARN("Failed to create workdir");
> + }
> +
> + free(containerdir);
> + lxc_free_array((void **)opts, free);
> + return 0;
> +}
> +
> +static int mount_entry_create_aufs_dirs(const struct mntent *mntent,
> + const struct lxc_rootfs *rootfs)
> +{
> + char *containerdir = NULL;
> + char *del = NULL;
> + char *scratch = NULL;
> + char *tmp = NULL;
> + char *upperdir = NULL;
> + char **opts = NULL;
> + size_t arrlen = 0;
> + size_t dirlen = 0;
> + size_t i;
> + size_t len = 0;
> + size_t rootfslen = 0;
> +
> + opts = lxc_string_split(mntent->mnt_opts, ',');
> + if (opts)
> + arrlen = lxc_array_len((void **)opts);
> + else
> + return -1;
> +
> + for (i = 0; i < arrlen; i++) {
> + if (strstr(opts[i], "br=") && (strlen(opts[i]) > (len = strlen("br="))))
> + tmp = opts[i] + len;
> + }
> + if (!tmp) {
> + lxc_free_array((void **)opts, free);
> + return -1;
> + }
> +
> + upperdir = strtok_r(tmp, ":=", &scratch);
> + if (!upperdir) {
> + lxc_free_array((void **)opts, free);
> + return -1;
> + }
> +
> + containerdir = strdup(rootfs->path);
> + if (!containerdir) {
> + lxc_free_array((void **)opts, free);
> + return -1;
> + }
> +
> + if ((del = strstr(containerdir, "/rootfs"))) {
> + memmove(del, del + 7, strlen(del) - 7 + 1);
> + }
> +
> + dirlen = strlen(containerdir);
> + rootfslen = strlen(rootfs->path);
> +
> + /* We neither allow users to create upperdirs outside the containerdir
> + * nor inside the rootfs. The latter might be debatable. */
> + if ((strncmp(upperdir, containerdir, dirlen) == 0) && (strncmp(upperdir, rootfs->path, rootfslen) != 0))
> + if (mkdir_p(upperdir, 0755) < 0) {
> + WARN("Failed to create upperdir");
> + }
> +
> + free(containerdir);
> + lxc_free_array((void **)opts, free);
> + return 0;
> +}
> +
> static int mount_entry_create_dir_file(const struct mntent *mntent,
> - const char* path)
> + const char* path, const struct lxc_rootfs *rootfs)
> {
> char *pathdirname = NULL;
> int ret = 0;
> FILE *pathfile = NULL;
>
> + if (strncmp(mntent->mnt_type, "overlay", 7) == 0) {
> + if (mount_entry_create_overlay_dirs(mntent, rootfs) < 0)
> + ret = -1;
> + } else if (strncmp(mntent->mnt_type, "aufs", 4) == 0) {
> + if (mount_entry_create_aufs_dirs(mntent, rootfs) < 0)
> + ret = -1;
> + }
Why if mount_entry_create_*_dirs() failed to you continue to try to
create the file? Seems better to simply return -1 right there.
> +
> if (hasmntopt(mntent, "create=dir")) {
> if (mkdir_p(path, 0755) < 0) {
> WARN("Failed to create mount target '%s'", path);
> @@ -1837,23 +1966,23 @@ static int mount_entry_create_dir_file(const struct mntent *mntent,
> if (!pathfile) {
> WARN("Failed to create mount target '%s'", path);
> ret = -1;
> - }
> - else
> + } else {
> fclose(pathfile);
> + }
> }
> free(pathdirname);
> return ret;
> }
>
> static inline int mount_entry_on_generic(struct mntent *mntent,
> - const char* path, const char *rootfs)
> + const char* path, const struct lxc_rootfs *rootfs)
> {
> unsigned long mntflags;
> char *mntdata;
> int ret;
> bool optional = hasmntopt(mntent, "optional") != NULL;
>
> - ret = mount_entry_create_dir_file(mntent, path);
> + ret = mount_entry_create_dir_file(mntent, path, rootfs);
>
> if (ret < 0)
> return optional ? 0 : -1;
> @@ -1865,11 +1994,11 @@ static inline int mount_entry_on_generic(struct mntent *mntent,
> return -1;
> }
>
> - ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type,
> - mntflags, mntdata, optional, rootfs);
> + ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, mntflags,
> + mntdata, optional,
> + rootfs->mount ? rootfs->mount : NULL);
This isn't right. Normally it's done as
rootfs->path ? rootfs->mount : NULL
because rootfs->mount is always allocated. If no rootfs was
specified it will be LXCROOTFSMOUNT which is something like
$libdir/lxc/rootfs.
This is obviously begging for a cleanup, but this patch isn't
the place to do that.
>
> free(mntdata);
> -
> return ret;
> }
>
> @@ -1922,17 +2051,17 @@ skipabs:
> return -1;
> }
>
> - return mount_entry_on_generic(mntent, path, rootfs->mount);
> + return mount_entry_on_generic(mntent, path, rootfs);
> }
>
> static int mount_entry_on_relative_rootfs(struct mntent *mntent,
> - const char *rootfs)
> + const struct lxc_rootfs *rootfs)
> {
> char path[MAXPATHLEN];
> int ret;
>
> /* relative to root mount point */
> - ret = snprintf(path, sizeof(path), "%s/%s", rootfs, mntent->mnt_dir);
> + ret = snprintf(path, sizeof(path), "%s/%s", rootfs->mount, mntent->mnt_dir);
> if (ret >= sizeof(path)) {
> ERROR("path name too long");
> return -1;
> @@ -1959,7 +2088,7 @@ static int mount_file_entries(const struct lxc_rootfs *rootfs, FILE *file,
> /* We have a separate root, mounts are relative to it */
> if (mntent.mnt_dir[0] != '/') {
> if (mount_entry_on_relative_rootfs(&mntent,
> - rootfs->mount))
> + rootfs))
> goto out;
> continue;
> }
> --
> 2.6.0
>
> _______________________________________________
> lxc-devel mailing list
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel
More information about the lxc-devel
mailing list