[lxc-devel] [PATCH] bdev: Add aufs support

Serge Hallyn serge.hallyn at ubuntu.com
Wed Feb 12 21:33:56 UTC 2014


Quoting Stéphane Graber (stgraber at ubuntu.com):
> This is pretty much copy/paste from overlayfs.

Most of that can probably consolidated with short wrappers for
each of aufs and overlayfs - which woudl be more worth it if
we expected a third :)

One question - you added aufs to the unprivileged-allowed
clones.  Are you hoping we get that working in the kernel?

> Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>

Acked-by: Serge E. Hallyn <serge.hallyn at ubuntu.com>

> ---
>  doc/lxc-clone.sgml.in    |  10 +-
>  doc/lxc-snapshot.sgml.in |   2 +-
>  src/lxc/bdev.c           | 261 ++++++++++++++++++++++++++++++++++++++++++++++-
>  src/lxc/bdev.h           |   4 +-
>  src/lxc/conf.c           |   2 +-
>  src/lxc/lxc_clone.c      |   2 +-
>  src/lxc/lxccontainer.c   |  12 ++-
>  src/lxc/lxccontainer.h   |   2 +-
>  8 files changed, 276 insertions(+), 19 deletions(-)
> 
> diff --git a/doc/lxc-clone.sgml.in b/doc/lxc-clone.sgml.in
> index 7b50094..13a5cf8 100644
> --- a/doc/lxc-clone.sgml.in
> +++ b/doc/lxc-clone.sgml.in
> @@ -88,15 +88,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>        snapshot filesystem uses the backing store's snapshot functionality to create
>        a very small copy-on-write snapshot of the original container.  Snapshot
>        clones require the new container backing store to support snapshotting.  Currently
> -      this includes only btrfs, lvm, overlayfs and zfs.  LVM devices do not support
> +      this includes only aufs, btrfs, lvm, overlayfs and zfs.  LVM devices do not support
>        snapshots of snapshots.
>      </para>
>  
>      <para>
>        The backing store of the new container will be the same type as the
>        original container,
> -      with one exception:  overlayfs snapshots can be created of directory backed
> -      containers.  This can be requested by using the <replaceable>-B overlayfs</replaceable>
> +      with one exception:  aufs and overlayfs snapshots can be created of directory backed
> +      containers.  This can be requested by using (for overlayfs) the <replaceable>-B overlayfs</replaceable>
>        arguments.
>      </para>
>  
> @@ -210,8 +210,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>  	    Select a different backing store for the new container.  By
>  	    default the same as the original container's is used.  Note that
>  	    currently changing the backingstore is only supported for
> -	    overlayfs snapshots of directory backed containers.  Valid
> -	    backing stores include dir (directory), btrfs, lvm, zfs, loop
> +	    aufs and overlayfs snapshots of directory backed containers.  Valid
> +	    backing stores include dir (directory), aufs, btrfs, lvm, zfs, loop
>  	    and overlayfs.
>  	  </para>
>  	</listitem>
> diff --git a/doc/lxc-snapshot.sgml.in b/doc/lxc-snapshot.sgml.in
> index f66070b..4b70279 100644
> --- a/doc/lxc-snapshot.sgml.in
> +++ b/doc/lxc-snapshot.sgml.in
> @@ -115,7 +115,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>  	  <varlistentry>
>  	    <term> <option>newname</option> </term>
>  	   <listitem>
> -	    <para> When restoring a snapshot, the last optional argument is the name to use for the restored container.  If no name is given, then the original container will be destroyed and the restored container will take its place.  Note that deleting the original snapshot is not possible in the case of overlayfs or zfs backed snapshots.</para>
> +	    <para> When restoring a snapshot, the last optional argument is the name to use for the restored container.  If no name is given, then the original container will be destroyed and the restored container will take its place.  Note that deleting the original snapshot is not possible in the case of aufs, overlayfs or zfs backed snapshots.</para>
>  	   </listitem>
>  	  </varlistentry>
>  
> diff --git a/src/lxc/bdev.c b/src/lxc/bdev.c
> index 7f8ab9c..d2923f2 100644
> --- a/src/lxc/bdev.c
> +++ b/src/lxc/bdev.c
> @@ -447,7 +447,7 @@ static int dir_clonepaths(struct bdev *orig, struct bdev *new, const char *oldna
>  	int len, ret;
>  
>  	if (snap) {
> -		ERROR("directories cannot be snapshotted.  Try overlayfs.");
> +		ERROR("directories cannot be snapshotted.  Try aufs or overlayfs.");
>  		return -1;
>  	}
>  
> @@ -1997,11 +1997,264 @@ static const struct bdev_ops overlayfs_ops = {
>  	.can_snapshot = true,
>  };
>  
> +//
> +// aufs ops
> +//
> +
> +static int aufs_detect(const char *path)
> +{
> +	if (strncmp(path, "aufs:", 5) == 0)
> +		return 1; // take their word for it
> +	return 0;
> +}
> +
> +//
> +// XXXXXXX plain directory bind mount ops
> +//
> +static int aufs_mount(struct bdev *bdev)
> +{
> +	char *options, *dup, *lower, *upper;
> +	int len;
> +	unsigned long mntflags;
> +	char *mntdata;
> +	int ret;
> +
> +	if (strcmp(bdev->type, "aufs"))
> +		return -22;
> +	if (!bdev->src || !bdev->dest)
> +		return -22;
> +
> +	//  separately mount it first
> +	//  mount -t aufs -obr=${upper}=rw:${lower}=ro lower dest
> +	dup = alloca(strlen(bdev->src)+1);
> +	strcpy(dup, bdev->src);
> +	if (!(lower = index(dup, ':')))
> +		return -22;
> +	if (!(upper = index(++lower, ':')))
> +		return -22;
> +	*upper = '\0';
> +	upper++;
> +
> +	if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
> +		free(mntdata);
> +		return -22;
> +	}
> +
> +	// TODO We should check whether bdev->src is a blockdev, and if so
> +	// but for now, only support aufs of a basic directory
> +
> +	if (mntdata) {
> +		len = strlen(lower) + strlen(upper) + strlen("br==rw:=ro,") + strlen(mntdata) + 1;
> +		options = alloca(len);
> +		ret = snprintf(options, len, "br=%s=rw:%s=ro,%s", upper, lower, mntdata);
> +	}
> +	else {
> +		len = strlen(lower) + strlen(upper) + strlen("br==rw:=ro") + 1;
> +		options = alloca(len);
> +		ret = snprintf(options, len, "br=%s=rw:%s=ro", upper, lower);
> +	}
> +	if (ret < 0 || ret >= len) {
> +		free(mntdata);
> +		return -1;
> +	}
> +
> +	ret = mount(lower, bdev->dest, "aufs", MS_MGC_VAL | mntflags, options);
> +	if (ret < 0)
> +		SYSERROR("aufs: error mounting %s onto %s options %s",
> +			lower, bdev->dest, options);
> +	else
> +		INFO("aufs: mounted %s onto %s options %s",
> +			lower, bdev->dest, options);
> +	return ret;
> +}
> +
> +static int aufs_umount(struct bdev *bdev)
> +{
> +	if (strcmp(bdev->type, "aufs"))
> +		return -22;
> +	if (!bdev->src || !bdev->dest)
> +		return -22;
> +	return umount(bdev->dest);
> +}
> +
> +static int aufs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
> +		const char *cname, const char *oldpath, const char *lxcpath, int snap,
> +		uint64_t newsize)
> +{
> +	if (!snap) {
> +		ERROR("aufs is only for snapshot clones");
> +		return -22;
> +	}
> +
> +	if (!orig->src || !orig->dest)
> +		return -1;
> +
> +	new->dest = dir_new_path(orig->dest, oldname, cname, oldpath, lxcpath);
> +	if (!new->dest)
> +		return -1;
> +	if (mkdir_p(new->dest, 0755) < 0)
> +		return -1;
> +
> +	if (strcmp(orig->type, "dir") == 0) {
> +		char *delta;
> +		int ret, len;
> +
> +		// if we have /var/lib/lxc/c2/rootfs, then delta will be
> +		//            /var/lib/lxc/c2/delta0
> +		delta = strdup(new->dest);
> +		if (!delta) {
> +			return -1;
> +		}
> +		if (strlen(delta) < 6) {
> +			free(delta);
> +			return -22;
> +		}
> +		strcpy(&delta[strlen(delta)-6], "delta0");
> +		if ((ret = mkdir(delta, 0755)) < 0) {
> +			SYSERROR("error: mkdir %s", delta);
> +			free(delta);
> +			return -1;
> +		}
> +
> +		// the src will be 'aufs:lowerdir:upperdir'
> +		len = strlen(delta) + strlen(orig->src) + 12;
> +		new->src = malloc(len);
> +		if (!new->src) {
> +			free(delta);
> +			return -ENOMEM;
> +		}
> +		ret = snprintf(new->src, len, "aufs:%s:%s", orig->src, delta);
> +		free(delta);
> +		if (ret < 0 || ret >= len)
> +			return -ENOMEM;
> +	} else if (strcmp(orig->type, "aufs") == 0) {
> +		// What exactly do we want to do here?
> +		// I think we want to use the original lowerdir, with a
> +		// private delta which is originally rsynced from the
> +		// original delta
> +		char *osrc, *odelta, *nsrc, *ndelta;
> +		int len, ret;
> +		if (!(osrc = strdup(orig->src)))
> +			return -22;
> +		nsrc = index(osrc, ':') + 1;
> +		if (nsrc != osrc + 5 || (odelta = index(nsrc, ':')) == NULL) {
> +			free(osrc);
> +			return -22;
> +		}
> +		*odelta = '\0';
> +		odelta++;
> +		ndelta = dir_new_path(odelta, oldname, cname, oldpath, lxcpath);
> +		if (!ndelta) {
> +			free(osrc);
> +			return -ENOMEM;
> +		}
> +		if (do_rsync(odelta, ndelta) < 0) {
> +			free(osrc);
> +			free(ndelta);
> +			ERROR("copying aufs delta");
> +			return -1;
> +		}
> +		len = strlen(nsrc) + strlen(ndelta) + 12;
> +		new->src = malloc(len);
> +		if (!new->src) {
> +			free(osrc);
> +			free(ndelta);
> +			return -ENOMEM;
> +		}
> +		ret = snprintf(new->src, len, "aufs:%s:%s", nsrc, ndelta);
> +		free(osrc);
> +		free(ndelta);
> +		if (ret < 0 || ret >= len)
> +			return -ENOMEM;
> +	} else {
> +		ERROR("aufs clone of %s container is not yet supported",
> +			orig->type);
> +		// Note, supporting this will require aufs_mount supporting
> +		// mounting of the underlay.  No big deal, just needs to be done.
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static int aufs_destroy(struct bdev *orig)
> +{
> +	char *upper;
> +
> +	if (strncmp(orig->src, "aufs:", 5) != 0)
> +		return -22;
> +	upper = index(orig->src + 5, ':');
> +	if (!upper)
> +		return -22;
> +	upper++;
> +	return lxc_rmdir_onedev(upper);
> +}
> +
> +/*
> + * to say 'lxc-create -t ubuntu -n o1 -B aufs' means you want
> + * $lxcpath/$lxcname/rootfs to have the created container, while all
> + * changes after starting the container are written to
> + * $lxcpath/$lxcname/delta0
> + */
> +static int aufs_create(struct bdev *bdev, const char *dest, const char *n,
> +			struct bdev_specs *specs)
> +{
> +	char *delta;
> +	int ret, len = strlen(dest), newlen;
> +
> +	if (len < 8 || strcmp(dest+len-7, "/rootfs") != 0)
> +		return -1;
> +
> +	if (!(bdev->dest = strdup(dest))) {
> +		ERROR("Out of memory");
> +		return -1;
> +	}
> +
> +	delta = alloca(strlen(dest)+1);
> +	strcpy(delta, dest);
> +	strcpy(delta+len-6, "delta0");
> +
> +	if (mkdir_p(delta, 0755) < 0) {
> +		ERROR("Error creating %s", delta);
> +		return -1;
> +	}
> +
> +	/* aufs:lower:upper */
> +	newlen = (2 * len) + strlen("aufs:") + 2;
> +	bdev->src = malloc(newlen);
> +	if (!bdev->src) {
> +		ERROR("Out of memory");
> +		return -1;
> +	}
> +	ret = snprintf(bdev->src, newlen, "aufs:%s:%s", dest, delta);
> +	if (ret < 0 || ret >= newlen)
> +		return -1;
> +
> +	if (mkdir_p(bdev->dest, 0755) < 0) {
> +		ERROR("Error creating %s", bdev->dest);
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct bdev_ops aufs_ops = {
> +	.detect = &aufs_detect,
> +	.mount = &aufs_mount,
> +	.umount = &aufs_umount,
> +	.clone_paths = &aufs_clonepaths,
> +	.destroy = &aufs_destroy,
> +	.create = &aufs_create,
> +	.can_snapshot = true,
> +};
> +
> +
>  static const struct bdev_type bdevs[] = {
>  	{.name = "zfs", .ops = &zfs_ops,},
>  	{.name = "lvm", .ops = &lvm_ops,},
>  	{.name = "btrfs", .ops = &btrfs_ops,},
>  	{.name = "dir", .ops = &dir_ops,},
> +	{.name = "aufs", .ops = &aufs_ops,},
>  	{.name = "overlayfs", .ops = &overlayfs_ops,},
>  	{.name = "loop", .ops = &loop_ops,},
>  };
> @@ -2140,6 +2393,7 @@ static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap,
>  		// (unless snap && b->type == dir, in which case it will be
>  		// overlayfs -- which is also allowed)
>  		if (strcmp(b->type, "dir") == 0 ||
> +				strcmp(b->type, "aufs") == 0 ||
>  				strcmp(b->type, "overlayfs") == 0 ||
>  				strcmp(b->type, "loop") == 0)
>  			return true;
> @@ -2227,7 +2481,8 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
>  
>  	*needs_rdep = 0;
>  	if (bdevtype && strcmp(orig->type, "dir") == 0 &&
> -			strcmp(bdevtype, "overlayfs") == 0)
> +			(strcmp(bdevtype, "aufs") == 0 ||
> +			 strcmp(bdevtype, "overlayfs") == 0))
>  		*needs_rdep = 1;
>  
>  	new = bdev_get(bdevtype ? bdevtype : orig->type);
> @@ -2339,7 +2594,7 @@ struct bdev *bdev_create(const char *dest, const char *type,
>  	return do_bdev_create(dest, type, cname, specs);
>  }
>  
> -char *overlayfs_getlower(char *p)
> +char *overlay_getlower(char *p)
>  {
>  	char *p1 = index(p, ':');
>  	if (p1)
> diff --git a/src/lxc/bdev.h b/src/lxc/bdev.h
> index e5d8523..250e320 100644
> --- a/src/lxc/bdev.h
> +++ b/src/lxc/bdev.h
> @@ -24,7 +24,7 @@
>  #ifndef __LXC_BDEV_H
>  #define __LXC_BDEV_H
>  /* blockdev operations for:
> - * dir, raw, btrfs, overlayfs, aufs, lvm, loop, zfs
> + * aufs, dir, raw, btrfs, overlayfs, aufs, lvm, loop, zfs
>   * someday: qemu-nbd, qcow2, qed
>   */
>  
> @@ -84,7 +84,7 @@ struct bdev {
>  	int lofd;
>  };
>  
> -char *overlayfs_getlower(char *p);
> +char *overlay_getlower(char *p);
>  
>  bool bdev_is_dir(const char *path);
>  
> diff --git a/src/lxc/conf.c b/src/lxc/conf.c
> index ecf2171..9e75633 100644
> --- a/src/lxc/conf.c
> +++ b/src/lxc/conf.c
> @@ -3346,7 +3346,7 @@ int chown_mapped_root(char *path, struct lxc_conf *conf)
>  	 * In case of overlay, we want only the writeable layer
>  	 * to be chowned
>  	 */
> -	if (strncmp(path, "overlayfs:", 10) == 0) {
> +	if (strncmp(path, "overlayfs:", 10) == 0 || strncmp(path, "aufs:", 5) == 0) {
>  		chownpath = strchr(path, ':');
>  		if (!chownpath) {
>  			ERROR("Bad overlay path: %s", path);
> diff --git a/src/lxc/lxc_clone.c b/src/lxc/lxc_clone.c
> index d7e6bc9..05579b8 100644
> --- a/src/lxc/lxc_clone.c
> +++ b/src/lxc/lxc_clone.c
> @@ -79,7 +79,7 @@ static void usage(const char *me)
>  	printf("\n");
>  	printf("  -s: snapshot rather than copy\n");
>  	printf("  -B: use specified new backingstore.  Default is the same as\n");
> -	printf("      the original.  Options include btrfs, lvm, overlayfs, \n");
> +	printf("      the original.  Options include aufs, btrfs, lvm, overlayfs, \n");
>  	printf("      dir and loop\n");
>  	printf("  -L: for blockdev-backed backingstore, use specified size * specified\n");
>  	printf("      unit. Default size is the size of the source blockdev, default\n");
> diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
> index 09d287b..51e0ac5 100644
> --- a/src/lxc/lxccontainer.c
> +++ b/src/lxc/lxccontainer.c
> @@ -891,13 +891,15 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet
>  
>  		src = c->lxc_conf->rootfs.path;
>  		/*
> -		 * for an overlayfs create, what the user wants is the template to fill
> +		 * for an overlay create, what the user wants is the template to fill
>  		 * in what will become the readonly lower layer.  So don't mount for
>  		 * the template
>  		 */
> -		if (strncmp(src, "overlayfs:", 10) == 0) {
> -			src = overlayfs_getlower(src+10);
> -		}
> +		if (strncmp(src, "overlayfs:", 10) == 0)
> +			src = overlay_getlower(src+10);
> +		if (strncmp(src, "aufs:", 5) == 0)
> +			src = overlay_getlower(src+5);
> +
>  		bdev = bdev_init(src, c->lxc_conf->rootfs.mount, NULL);
>  		if (!bdev) {
>  			ERROR("Error opening rootfs");
> @@ -2830,7 +2832,7 @@ static int lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
>  	if (bdev_is_dir(c->lxc_conf->rootfs.path)) {
>  		ERROR("Snapshot of directory-backed container requested.");
>  		ERROR("Making a copy-clone.  If you do want snapshots, then");
> -		ERROR("please create an overlayfs clone first, snapshot that");
> +		ERROR("please create an aufs or overlayfs clone first, snapshot that");
>  		ERROR("and keep the original container pristine.");
>  		flags &= ~LXC_CLONE_SNAPSHOT | LXC_CLONE_MAYBE_SNAPSHOT;
>  	}
> diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
> index 92c76b4..b9873eb 100644
> --- a/src/lxc/lxccontainer.h
> +++ b/src/lxc/lxccontainer.h
> @@ -688,7 +688,7 @@ struct lxc_container {
>  	 * \return \c true on success, else \c false.
>  	 * \warning If \p newname is the same as the current container
>  	 *  name, the container will be destroyed. However, this will
> -	 *  fail if the  snapshot is overlayfs-based, since the snapshots
> +	 *  fail if the  snapshot is overlay-based, since the snapshots
>  	 *  will pin the original container.
>  	 * \note As an example, if the container exists as \c /var/lib/lxc/c1, snapname might be \c 'snap0'
>  	 *  (representing \c /var/lib/lxcsnaps/c1/snap0). If \p newname is \p c2,
> -- 
> 1.9.rc1
> 
> _______________________________________________
> 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