]> git.proxmox.com Git - mirror_lxc.git/commitdiff
bdev: Add aufs support
authorStéphane Graber <stgraber@ubuntu.com>
Wed, 12 Feb 2014 19:01:02 +0000 (14:01 -0500)
committerStéphane Graber <stgraber@ubuntu.com>
Wed, 12 Feb 2014 21:43:55 +0000 (16:43 -0500)
This is pretty much copy/paste from overlayfs.

Signed-off-by: Stéphane Graber <stgraber@ubuntu.com>
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
doc/lxc-clone.sgml.in
doc/lxc-snapshot.sgml.in
src/lxc/bdev.c
src/lxc/bdev.h
src/lxc/conf.c
src/lxc/lxc_clone.c
src/lxc/lxccontainer.c
src/lxc/lxccontainer.h

index 7b50094f40acb5b395a964ae613e18fead620b5d..13a5cf89de12a50e78e0742ab3ff2ad82fdc1c7d 100644 (file)
@@ -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>
index f66070b1a73be27de5fd3b92c32e5e47dc0e9e23..4b70279fa033b7fa1b348a9086100c3fa81522b0 100644 (file)
@@ -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>
 
index 7f8ab9cba6d2fb6942dc46eb22be65d23a67b3f7..1df602c7fdb7b92221217d7a1ecb8a3dd28b1edc 100644 (file)
@@ -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,},
 };
@@ -2227,7 +2480,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 +2593,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)
index e5d8523443768f9cc57edcf5a73606df0625288b..250e3209c4e1f3728b6bbfe98a6c90379d8778ab 100644 (file)
@@ -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);
 
index ecf2171fc6e9bf5011bc98733ce1524757067b3f..9e756335997c43e06dd1a8f61a504591ebc1b4d5 100644 (file)
@@ -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);
index d7e6bc93d8ad660554b859a1282ce424df4f8cde..05579b84b1974a1aa962aaa50437b7a81fede681 100644 (file)
@@ -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");
index 09d287bd944b3ce117e6cf26abd7c75e57175cc9..51e0ac575b76c902535b1c5e8518c998d090f987 100644 (file)
@@ -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;
        }
index 92c76b45b68e70b26e1de5af66ef19987e00e235..b9873ebece6c274edd2435300869a5e841b1d0cf 100644 (file)
@@ -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,