2
0
mirror of git://github.com/lxc/lxc synced 2025-08-31 00:09:37 +00:00

bdev: Add aufs support

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>
This commit is contained in:
Stéphane Graber
2014-02-12 14:01:02 -05:00
parent e40bb7f458
commit 1f92162dc0
8 changed files with 275 additions and 19 deletions

View 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 snapshot filesystem uses the backing store's snapshot functionality to create
a very small copy-on-write snapshot of the original container. Snapshot a very small copy-on-write snapshot of the original container. Snapshot
clones require the new container backing store to support snapshotting. Currently 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. snapshots of snapshots.
</para> </para>
<para> <para>
The backing store of the new container will be the same type as the The backing store of the new container will be the same type as the
original container, original container,
with one exception: overlayfs snapshots can be created of directory backed with one exception: aufs and overlayfs snapshots can be created of directory backed
containers. This can be requested by using the <replaceable>-B overlayfs</replaceable> containers. This can be requested by using (for overlayfs) the <replaceable>-B overlayfs</replaceable>
arguments. arguments.
</para> </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 Select a different backing store for the new container. By
default the same as the original container's is used. Note that default the same as the original container's is used. Note that
currently changing the backingstore is only supported for currently changing the backingstore is only supported for
overlayfs snapshots of directory backed containers. Valid aufs and overlayfs snapshots of directory backed containers. Valid
backing stores include dir (directory), btrfs, lvm, zfs, loop backing stores include dir (directory), aufs, btrfs, lvm, zfs, loop
and overlayfs. and overlayfs.
</para> </para>
</listitem> </listitem>

View File

@@ -115,7 +115,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<varlistentry> <varlistentry>
<term> <option>newname</option> </term> <term> <option>newname</option> </term>
<listitem> <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> </listitem>
</varlistentry> </varlistentry>

View File

@@ -447,7 +447,7 @@ static int dir_clonepaths(struct bdev *orig, struct bdev *new, const char *oldna
int len, ret; int len, ret;
if (snap) { if (snap) {
ERROR("directories cannot be snapshotted. Try overlayfs."); ERROR("directories cannot be snapshotted. Try aufs or overlayfs.");
return -1; return -1;
} }
@@ -1997,11 +1997,264 @@ static const struct bdev_ops overlayfs_ops = {
.can_snapshot = true, .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[] = { static const struct bdev_type bdevs[] = {
{.name = "zfs", .ops = &zfs_ops,}, {.name = "zfs", .ops = &zfs_ops,},
{.name = "lvm", .ops = &lvm_ops,}, {.name = "lvm", .ops = &lvm_ops,},
{.name = "btrfs", .ops = &btrfs_ops,}, {.name = "btrfs", .ops = &btrfs_ops,},
{.name = "dir", .ops = &dir_ops,}, {.name = "dir", .ops = &dir_ops,},
{.name = "aufs", .ops = &aufs_ops,},
{.name = "overlayfs", .ops = &overlayfs_ops,}, {.name = "overlayfs", .ops = &overlayfs_ops,},
{.name = "loop", .ops = &loop_ops,}, {.name = "loop", .ops = &loop_ops,},
}; };
@@ -2227,7 +2480,8 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
*needs_rdep = 0; *needs_rdep = 0;
if (bdevtype && strcmp(orig->type, "dir") == 0 && if (bdevtype && strcmp(orig->type, "dir") == 0 &&
strcmp(bdevtype, "overlayfs") == 0) (strcmp(bdevtype, "aufs") == 0 ||
strcmp(bdevtype, "overlayfs") == 0))
*needs_rdep = 1; *needs_rdep = 1;
new = bdev_get(bdevtype ? bdevtype : orig->type); 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); return do_bdev_create(dest, type, cname, specs);
} }
char *overlayfs_getlower(char *p) char *overlay_getlower(char *p)
{ {
char *p1 = index(p, ':'); char *p1 = index(p, ':');
if (p1) if (p1)

View File

@@ -24,7 +24,7 @@
#ifndef __LXC_BDEV_H #ifndef __LXC_BDEV_H
#define __LXC_BDEV_H #define __LXC_BDEV_H
/* blockdev operations for: /* 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 * someday: qemu-nbd, qcow2, qed
*/ */
@@ -84,7 +84,7 @@ struct bdev {
int lofd; int lofd;
}; };
char *overlayfs_getlower(char *p); char *overlay_getlower(char *p);
bool bdev_is_dir(const char *path); bool bdev_is_dir(const char *path);

View 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 * In case of overlay, we want only the writeable layer
* to be chowned * to be chowned
*/ */
if (strncmp(path, "overlayfs:", 10) == 0) { if (strncmp(path, "overlayfs:", 10) == 0 || strncmp(path, "aufs:", 5) == 0) {
chownpath = strchr(path, ':'); chownpath = strchr(path, ':');
if (!chownpath) { if (!chownpath) {
ERROR("Bad overlay path: %s", path); ERROR("Bad overlay path: %s", path);

View File

@@ -79,7 +79,7 @@ static void usage(const char *me)
printf("\n"); printf("\n");
printf(" -s: snapshot rather than copy\n"); printf(" -s: snapshot rather than copy\n");
printf(" -B: use specified new backingstore. Default is the same as\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(" dir and loop\n");
printf(" -L: for blockdev-backed backingstore, use specified size * specified\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"); printf(" unit. Default size is the size of the source blockdev, default\n");

View File

@@ -891,13 +891,15 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet
src = c->lxc_conf->rootfs.path; 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 * in what will become the readonly lower layer. So don't mount for
* the template * the template
*/ */
if (strncmp(src, "overlayfs:", 10) == 0) { if (strncmp(src, "overlayfs:", 10) == 0)
src = overlayfs_getlower(src+10); 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); bdev = bdev_init(src, c->lxc_conf->rootfs.mount, NULL);
if (!bdev) { if (!bdev) {
ERROR("Error opening rootfs"); 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)) { if (bdev_is_dir(c->lxc_conf->rootfs.path)) {
ERROR("Snapshot of directory-backed container requested."); ERROR("Snapshot of directory-backed container requested.");
ERROR("Making a copy-clone. If you do want snapshots, then"); 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."); ERROR("and keep the original container pristine.");
flags &= ~LXC_CLONE_SNAPSHOT | LXC_CLONE_MAYBE_SNAPSHOT; flags &= ~LXC_CLONE_SNAPSHOT | LXC_CLONE_MAYBE_SNAPSHOT;
} }

View File

@@ -688,7 +688,7 @@ struct lxc_container {
* \return \c true on success, else \c false. * \return \c true on success, else \c false.
* \warning If \p newname is the same as the current container * \warning If \p newname is the same as the current container
* name, the container will be destroyed. However, this will * 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. * will pin the original container.
* \note As an example, if the container exists as \c /var/lib/lxc/c1, snapname might be \c 'snap0' * \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, * (representing \c /var/lib/lxcsnaps/c1/snap0). If \p newname is \p c2,