mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-07-27 12:37:35 +00:00
Split bdev into modules: lxcaufs
The functions - aufs_clonepaths(); - aufs_create(); - aufs_destroy(); - aufs_detect(); - aufs_mount(); - aufs_umount(); move from bdev.c to lxcaufs.{c,h}. All functions which previously were static become extern. Adapt Makefile.am to include lxcaufs.{c,h}. The structs - struct bdev; /* defined in bdev.h */ - struct bdev_specs; /* defined in lxccontainer.h */ - struct lxc_conf; /* defined conf.h */ are forward declared/put as incomplete types into lxcaufs.h as the functions associated with aufs need access to it. Signed-off-by: Christian Brauner <christian.brauner@mailbox.org>
This commit is contained in:
parent
2b9cbd533d
commit
00f0a1f896
@ -7,6 +7,7 @@ noinst_HEADERS = \
|
|||||||
arguments.h \
|
arguments.h \
|
||||||
attach.h \
|
attach.h \
|
||||||
bdev/bdev.h \
|
bdev/bdev.h \
|
||||||
|
bdev/lxcaufs.h \
|
||||||
bdev/lxcbtrfs.h \
|
bdev/lxcbtrfs.h \
|
||||||
bdev/lxclvm.h \
|
bdev/lxclvm.h \
|
||||||
bdev/lxcoverlay.h \
|
bdev/lxcoverlay.h \
|
||||||
@ -65,6 +66,7 @@ endif
|
|||||||
liblxc_so_SOURCES = \
|
liblxc_so_SOURCES = \
|
||||||
arguments.c arguments.h \
|
arguments.c arguments.h \
|
||||||
bdev/bdev.c bdev/bdev.h \
|
bdev/bdev.c bdev/bdev.h \
|
||||||
|
bdev/lxcaufs.c bdev/lxcaufs.h \
|
||||||
bdev/lxcbtrfs.c bdev/lxcbtrfs.h \
|
bdev/lxcbtrfs.c bdev/lxcbtrfs.h \
|
||||||
bdev/lxclvm.c bdev/lxclvm.h \
|
bdev/lxclvm.c bdev/lxclvm.h \
|
||||||
bdev/lxcoverlay.c bdev/lxcoverlay.h \
|
bdev/lxcoverlay.c bdev/lxcoverlay.h \
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "lxc.h"
|
#include "lxc.h"
|
||||||
|
#include "lxcaufs.h"
|
||||||
#include "lxcbtrfs.h"
|
#include "lxcbtrfs.h"
|
||||||
#include "lxclock.h"
|
#include "lxclock.h"
|
||||||
#include "lxclvm.h"
|
#include "lxclvm.h"
|
||||||
@ -77,6 +78,18 @@
|
|||||||
|
|
||||||
lxc_log_define(bdev, lxc);
|
lxc_log_define(bdev, lxc);
|
||||||
|
|
||||||
|
/* aufs */
|
||||||
|
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,
|
||||||
|
.can_backup = true,
|
||||||
|
};
|
||||||
|
|
||||||
/* btrfs */
|
/* btrfs */
|
||||||
static const struct bdev_ops btrfs_ops = {
|
static const struct bdev_ops btrfs_ops = {
|
||||||
.detect = &btrfs_detect,
|
.detect = &btrfs_detect,
|
||||||
@ -125,18 +138,6 @@ static const struct bdev_ops zfs_ops = {
|
|||||||
.can_backup = true,
|
.can_backup = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* functions associated with an aufs bdev struct */
|
|
||||||
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, struct lxc_conf *conf);
|
|
||||||
static int aufs_create(struct bdev *bdev, const char *dest, const char *n,
|
|
||||||
struct bdev_specs *specs);
|
|
||||||
static int aufs_destroy(struct bdev *orig);
|
|
||||||
static int aufs_detect(const char *path);
|
|
||||||
static int aufs_mount(struct bdev *bdev);
|
|
||||||
static int aufs_umount(struct bdev *bdev);
|
|
||||||
|
|
||||||
/* functions associated with a dir bdev struct */
|
/* functions associated with a dir bdev struct */
|
||||||
static int dir_clonepaths(struct bdev *orig, struct bdev *new,
|
static int dir_clonepaths(struct bdev *orig, struct bdev *new,
|
||||||
const char *oldname, const char *cname,
|
const char *oldname, const char *cname,
|
||||||
@ -209,7 +210,7 @@ static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap,
|
|||||||
|
|
||||||
/* the bulk of this needs to become a common helper */
|
/* the bulk of this needs to become a common helper */
|
||||||
char *dir_new_path(char *src, const char *oldname, const char *name,
|
char *dir_new_path(char *src, const char *oldname, const char *name,
|
||||||
const char *oldpath, const char *lxcpath)
|
const char *oldpath, const char *lxcpath)
|
||||||
{
|
{
|
||||||
char *ret, *p, *p2;
|
char *ret, *p, *p2;
|
||||||
int l1, l2, nlen;
|
int l1, l2, nlen;
|
||||||
@ -1083,293 +1084,6 @@ static const struct bdev_ops loop_ops = {
|
|||||||
.can_backup = true,
|
.can_backup = 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;
|
|
||||||
const char *xinopath = "/dev/shm/aufs.xino";
|
|
||||||
|
|
||||||
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 = strchr(dup, ':')))
|
|
||||||
return -22;
|
|
||||||
if (!(upper = strchr(++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
|
|
||||||
|
|
||||||
// AUFS does not work on top of certain filesystems like (XFS or Btrfs)
|
|
||||||
// so add xino=/dev/shm/aufs.xino parameter to mount options.
|
|
||||||
// The same xino option can be specified to multiple aufs mounts, and
|
|
||||||
// a xino file is not shared among multiple aufs mounts.
|
|
||||||
//
|
|
||||||
// see http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg02587.html
|
|
||||||
// http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg05126.html
|
|
||||||
if (mntdata) {
|
|
||||||
len = strlen(lower) + strlen(upper) + strlen(xinopath) + strlen("br==rw:=ro,,xino=") + strlen(mntdata) + 1;
|
|
||||||
options = alloca(len);
|
|
||||||
ret = snprintf(options, len, "br=%s=rw:%s=ro,%s,xino=%s", upper, lower, mntdata, xinopath);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
len = strlen(lower) + strlen(upper) + strlen(xinopath) + strlen("br==rw:=ro,xino=") + 1;
|
|
||||||
options = alloca(len);
|
|
||||||
ret = snprintf(options, len, "br=%s=rw:%s=ro,xino=%s", upper, lower, xinopath);
|
|
||||||
}
|
|
||||||
|
|
||||||
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, struct lxc_conf *conf)
|
|
||||||
{
|
|
||||||
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 (am_unpriv() && chown_mapped_root(new->dest, conf) < 0)
|
|
||||||
WARN("Failed to update ownership of %s", new->dest);
|
|
||||||
|
|
||||||
if (strcmp(orig->type, "dir") == 0) {
|
|
||||||
char *delta, *lastslash;
|
|
||||||
int ret, len, lastslashidx;
|
|
||||||
|
|
||||||
// if we have /var/lib/lxc/c2/rootfs, then delta will be
|
|
||||||
// /var/lib/lxc/c2/delta0
|
|
||||||
lastslash = strrchr(new->dest, '/');
|
|
||||||
if (!lastslash)
|
|
||||||
return -22;
|
|
||||||
if (strlen(lastslash) < 7)
|
|
||||||
return -22;
|
|
||||||
lastslash++;
|
|
||||||
lastslashidx = lastslash - new->dest;
|
|
||||||
|
|
||||||
delta = malloc(lastslashidx + 7);
|
|
||||||
if (!delta)
|
|
||||||
return -1;
|
|
||||||
strncpy(delta, new->dest, lastslashidx+1);
|
|
||||||
strcpy(delta+lastslashidx, "delta0");
|
|
||||||
if ((ret = mkdir(delta, 0755)) < 0) {
|
|
||||||
SYSERROR("error: mkdir %s", delta);
|
|
||||||
free(delta);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (am_unpriv() && chown_mapped_root(delta, conf) < 0)
|
|
||||||
WARN("Failed to update ownership of %s", delta);
|
|
||||||
|
|
||||||
// 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 = strchr(osrc, ':') + 1;
|
|
||||||
if (nsrc != osrc + 5 || (odelta = strchr(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 ((ret = mkdir(ndelta, 0755)) < 0 && errno != EEXIST) {
|
|
||||||
SYSERROR("error: mkdir %s", ndelta);
|
|
||||||
free(osrc);
|
|
||||||
free(ndelta);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (am_unpriv() && chown_mapped_root(ndelta, conf) < 0)
|
|
||||||
WARN("Failed to update ownership of %s", ndelta);
|
|
||||||
|
|
||||||
struct rsync_data_char rdata;
|
|
||||||
rdata.src = odelta;
|
|
||||||
rdata.dest = ndelta;
|
|
||||||
if (am_unpriv())
|
|
||||||
ret = userns_exec_1(conf, rsync_delta_wrapper, &rdata);
|
|
||||||
else
|
|
||||||
ret = rsync_delta(&rdata);
|
|
||||||
if (ret) {
|
|
||||||
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 = strchr(orig->src + 5, ':');
|
|
||||||
if (!upper)
|
|
||||||
return -22;
|
|
||||||
upper++;
|
|
||||||
return lxc_rmdir_onedev(upper, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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,
|
|
||||||
.can_backup = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// nbd dev ops
|
// nbd dev ops
|
||||||
//
|
//
|
||||||
|
308
src/lxc/bdev/lxcaufs.c
Normal file
308
src/lxc/bdev/lxcaufs.c
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
/*
|
||||||
|
* lxc: linux Container library
|
||||||
|
*
|
||||||
|
* (C) Copyright IBM Corp. 2007, 2008
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Daniel Lezcano <daniel.lezcano at free.fr>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "bdev.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "lxcrsync.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
lxc_log_define(lxcaufs, lxc);
|
||||||
|
|
||||||
|
/* the bulk of this needs to become a common helper */
|
||||||
|
extern char *dir_new_path(char *src, const char *oldname, const char *name,
|
||||||
|
const char *oldpath, const char *lxcpath);
|
||||||
|
|
||||||
|
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, struct lxc_conf *conf)
|
||||||
|
{
|
||||||
|
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 (am_unpriv() && chown_mapped_root(new->dest, conf) < 0)
|
||||||
|
WARN("Failed to update ownership of %s", new->dest);
|
||||||
|
|
||||||
|
if (strcmp(orig->type, "dir") == 0) {
|
||||||
|
char *delta, *lastslash;
|
||||||
|
int ret, len, lastslashidx;
|
||||||
|
|
||||||
|
// if we have /var/lib/lxc/c2/rootfs, then delta will be
|
||||||
|
// /var/lib/lxc/c2/delta0
|
||||||
|
lastslash = strrchr(new->dest, '/');
|
||||||
|
if (!lastslash)
|
||||||
|
return -22;
|
||||||
|
if (strlen(lastslash) < 7)
|
||||||
|
return -22;
|
||||||
|
lastslash++;
|
||||||
|
lastslashidx = lastslash - new->dest;
|
||||||
|
|
||||||
|
delta = malloc(lastslashidx + 7);
|
||||||
|
if (!delta)
|
||||||
|
return -1;
|
||||||
|
strncpy(delta, new->dest, lastslashidx+1);
|
||||||
|
strcpy(delta+lastslashidx, "delta0");
|
||||||
|
if ((ret = mkdir(delta, 0755)) < 0) {
|
||||||
|
SYSERROR("error: mkdir %s", delta);
|
||||||
|
free(delta);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (am_unpriv() && chown_mapped_root(delta, conf) < 0)
|
||||||
|
WARN("Failed to update ownership of %s", delta);
|
||||||
|
|
||||||
|
// 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 = strchr(osrc, ':') + 1;
|
||||||
|
if (nsrc != osrc + 5 || (odelta = strchr(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 ((ret = mkdir(ndelta, 0755)) < 0 && errno != EEXIST) {
|
||||||
|
SYSERROR("error: mkdir %s", ndelta);
|
||||||
|
free(osrc);
|
||||||
|
free(ndelta);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (am_unpriv() && chown_mapped_root(ndelta, conf) < 0)
|
||||||
|
WARN("Failed to update ownership of %s", ndelta);
|
||||||
|
|
||||||
|
struct rsync_data_char rdata;
|
||||||
|
rdata.src = odelta;
|
||||||
|
rdata.dest = ndelta;
|
||||||
|
if (am_unpriv())
|
||||||
|
ret = userns_exec_1(conf, rsync_delta_wrapper, &rdata);
|
||||||
|
else
|
||||||
|
ret = rsync_delta(&rdata);
|
||||||
|
if (ret) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int aufs_destroy(struct bdev *orig)
|
||||||
|
{
|
||||||
|
char *upper;
|
||||||
|
|
||||||
|
if (strncmp(orig->src, "aufs:", 5) != 0)
|
||||||
|
return -22;
|
||||||
|
upper = strchr(orig->src + 5, ':');
|
||||||
|
if (!upper)
|
||||||
|
return -22;
|
||||||
|
upper++;
|
||||||
|
return lxc_rmdir_onedev(upper, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int aufs_detect(const char *path)
|
||||||
|
{
|
||||||
|
if (strncmp(path, "aufs:", 5) == 0)
|
||||||
|
return 1; // take their word for it
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int aufs_mount(struct bdev *bdev)
|
||||||
|
{
|
||||||
|
char *options, *dup, *lower, *upper;
|
||||||
|
int len;
|
||||||
|
unsigned long mntflags;
|
||||||
|
char *mntdata;
|
||||||
|
int ret;
|
||||||
|
const char *xinopath = "/dev/shm/aufs.xino";
|
||||||
|
|
||||||
|
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 = strchr(dup, ':')))
|
||||||
|
return -22;
|
||||||
|
if (!(upper = strchr(++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
|
||||||
|
|
||||||
|
// AUFS does not work on top of certain filesystems like (XFS or Btrfs)
|
||||||
|
// so add xino=/dev/shm/aufs.xino parameter to mount options.
|
||||||
|
// The same xino option can be specified to multiple aufs mounts, and
|
||||||
|
// a xino file is not shared among multiple aufs mounts.
|
||||||
|
//
|
||||||
|
// see http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg02587.html
|
||||||
|
// http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg05126.html
|
||||||
|
if (mntdata) {
|
||||||
|
len = strlen(lower) + strlen(upper) + strlen(xinopath) + strlen("br==rw:=ro,,xino=") + strlen(mntdata) + 1;
|
||||||
|
options = alloca(len);
|
||||||
|
ret = snprintf(options, len, "br=%s=rw:%s=ro,%s,xino=%s", upper, lower, mntdata, xinopath);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
len = strlen(lower) + strlen(upper) + strlen(xinopath) + strlen("br==rw:=ro,xino=") + 1;
|
||||||
|
options = alloca(len);
|
||||||
|
ret = snprintf(options, len, "br=%s=rw:%s=ro,xino=%s", upper, lower, xinopath);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int aufs_umount(struct bdev *bdev)
|
||||||
|
{
|
||||||
|
if (strcmp(bdev->type, "aufs"))
|
||||||
|
return -22;
|
||||||
|
if (!bdev->src || !bdev->dest)
|
||||||
|
return -22;
|
||||||
|
return umount(bdev->dest);
|
||||||
|
}
|
52
src/lxc/bdev/lxcaufs.h
Normal file
52
src/lxc/bdev/lxcaufs.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* lxc: linux Container library
|
||||||
|
*
|
||||||
|
* (C) Copyright IBM Corp. 2007, 2008
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Daniel Lezcano <daniel.lezcano at free.fr>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LXC_AUFS_H
|
||||||
|
#define __LXC_AUFS_H
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* defined in bdev.h */
|
||||||
|
struct bdev;
|
||||||
|
|
||||||
|
/* defined in lxccontainer.h */
|
||||||
|
struct bdev_specs;
|
||||||
|
|
||||||
|
/* defined conf.h */
|
||||||
|
struct lxc_conf;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Functions associated with an aufs bdev struct.
|
||||||
|
*/
|
||||||
|
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, struct lxc_conf *conf);
|
||||||
|
int aufs_create(struct bdev *bdev, const char *dest, const char *n,
|
||||||
|
struct bdev_specs *specs);
|
||||||
|
int aufs_destroy(struct bdev *orig);
|
||||||
|
int aufs_detect(const char *path);
|
||||||
|
int aufs_mount(struct bdev *bdev);
|
||||||
|
int aufs_umount(struct bdev *bdev);
|
||||||
|
|
||||||
|
#endif /* __LXC_AUFS_H */
|
Loading…
Reference in New Issue
Block a user