Skip to content

Commit

Permalink
bdev: Add aufs support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
stgraber committed Feb 12, 2014
1 parent e40bb7f commit 1f92162
Show file tree
Hide file tree
Showing 8 changed files with 275 additions and 19 deletions.
10 changes: 5 additions & 5 deletions doc/lxc-clone.sgml.in
Expand Up @@ -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>

Expand Down Expand Up @@ -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>
Expand Down
2 changes: 1 addition & 1 deletion doc/lxc-snapshot.sgml.in
Expand Up @@ -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>

Expand Down
260 changes: 257 additions & 3 deletions src/lxc/bdev.c
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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,},
};
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions src/lxc/bdev.h
Expand Up @@ -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
*/

Expand Down Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion src/lxc/conf.c
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/lxc/lxc_clone.c
Expand Up @@ -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");
Expand Down
12 changes: 7 additions & 5 deletions src/lxc/lxccontainer.c
Expand Up @@ -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");
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit 1f92162

Please sign in to comment.