Quoting Stéphane Graber ([email protected]):
> 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 <[email protected]>

Acked-by: Serge E. Hallyn <[email protected]>

> ---
>  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
> [email protected]
> http://lists.linuxcontainers.org/listinfo/lxc-devel
_______________________________________________
lxc-devel mailing list
[email protected]
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to