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
