overlay: rework overlay storage driver

parent 3ef1df7c
......@@ -45,8 +45,6 @@ static char *ovl_version[] = {"overlay", "overlayfs"};
static char *ovl_detect_name(void);
static int ovl_do_rsync(struct bdev *orig, struct bdev *new,
struct lxc_conf *conf);
static int ovl_rsync(struct rsync_data *data);
static int ovl_rsync_wrapper(void *data);
static int ovl_remount_on_enodev(const char *lower, const char *target,
const char *name, unsigned long mountflags,
const void *options);
......@@ -55,61 +53,80 @@ int ovl_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)
{
char *src;
int ret;
char *src;
if (!snap) {
ERROR("overlay is only for snapshot clones");
ERROR("The overlay storage driver can only be used for "
"snapshots");
return -22;
}
if (!orig->src || !orig->dest)
return -1;
new->dest = lxc_string_join(
"/", (const char *[]){lxcpath, cname, "rootfs", NULL}, false);
if (!new->dest)
return -1;
new->dest = must_make_path(lxcpath, cname, "rootfs", NULL);
if (mkdir_p(new->dest, 0755) < 0)
ret = mkdir_p(new->dest, 0755);
if (ret < 0 && errno != EEXIST) {
SYSERROR("Failed to create directory \"%s\"", new->dest);
return -1;
}
if (am_unpriv() && chown_mapped_root(new->dest, conf) < 0)
WARN("Failed to update ownership of %s", new->dest);
if (am_unpriv()) {
ret = chown_mapped_root(new->dest, conf);
if (ret < 0)
WARN("Failed to update ownership of %s", new->dest);
}
if (strcmp(orig->type, "dir") == 0) {
char *delta, *lastslash;
char *work;
int ret, len, lastslashidx;
/*
* if we have
* /var/lib/lxc/c2/rootfs
* then delta will be
* /var/lib/lxc/c2/delta0
/* If we have "/var/lib/lxc/c2/rootfs" then delta will be
* "/var/lib/lxc/c2/delta0".
*/
lastslash = strrchr(new->dest, '/');
if (!lastslash)
if (!lastslash) {
ERROR("Failed to detect \"/\" in string \"%s\"",
new->dest);
return -22;
if (strlen(lastslash) < 7)
}
if (strlen(lastslash) < (sizeof("/rootfs") - 1)) {
ERROR("Failed to detect \"/rootfs\" in string \"%s\"",
new->dest);
return -22;
}
lastslash++;
lastslashidx = lastslash - new->dest;
delta = malloc(lastslashidx + 7);
if (!delta)
if (!delta) {
ERROR("Failed to allocate memory");
return -1;
}
strncpy(delta, new->dest, lastslashidx + 1);
strcpy(delta + lastslashidx, "delta0");
if ((ret = mkdir(delta, 0755)) < 0) {
SYSERROR("error: mkdir %s", delta);
strncpy(delta + lastslashidx, "delta0", sizeof("delta0") - 1);
delta[lastslashidx + sizeof("delta0")] = '\0';
ret = mkdir(delta, 0755);
if (ret < 0 && errno != EEXIST) {
SYSERROR("Failed to create directory \"%s\"", delta);
free(delta);
return -1;
}
if (am_unpriv() && chown_mapped_root(delta, conf) < 0)
WARN("Failed to update ownership of %s", delta);
/*
* Make workdir for overlayfs.v22 or higher:
if (am_unpriv()) {
ret = chown_mapped_root(delta, conf);
if (ret < 0)
WARN("Failed to update ownership of %s", delta);
}
/* Make workdir for overlayfs.v22 or higher:
* The workdir will be
* /var/lib/lxc/c2/olwork
* and is used to prepare files before they are atomically
......@@ -119,86 +136,103 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
*/
work = malloc(lastslashidx + 7);
if (!work) {
ERROR("Failed to allocate memory");
free(delta);
return -1;
}
strncpy(work, new->dest, lastslashidx + 1);
strcpy(work + lastslashidx, "olwork");
strncpy(work + lastslashidx, "olwork", sizeof("olwork") - 1);
work[lastslashidx + sizeof("olwork")] = '\0';
if (mkdir(work, 0755) < 0) {
SYSERROR("error: mkdir %s", work);
free(delta);
free(work);
return -1;
}
if (am_unpriv() && chown_mapped_root(work, conf) < 0)
WARN("Failed to update ownership of %s", work);
if (am_unpriv()) {
ret = chown_mapped_root(work, conf);
if (ret < 0)
WARN("Failed to update ownership of %s", work);
}
free(work);
/* strlen("overlay:") = 8
* +
* strlen(delta)
* +
* :
* +
* strlen(src)
* +
* \0
*/
src = lxc_storage_get_path(orig->src, orig->type);
// the src will be 'overlayfs:lowerdir:upperdir'
len = strlen(delta) + strlen(src) + 12;
len = 8 + strlen(delta) + 1 + strlen(src) + 1;
new->src = malloc(len);
if (!new->src) {
ERROR("Failed to allocate memory");
free(delta);
return -ENOMEM;
}
ret = snprintf(new->src, len, "overlay:%s:%s", src, delta);
free(delta);
if (ret < 0 || ret >= len)
if (ret < 0 || (size_t)ret >= len) {
ERROR("Failed to create string");
return -1;
} else if (!strcmp(orig->type, "overlayfs") || !strcmp(orig->type, "overlay")) {
/*
* 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
*/
}
} else if (!strcmp(orig->type, "overlayfs") ||
!strcmp(orig->type, "overlay")) {
char *osrc, *odelta, *nsrc, *ndelta, *work;
char *lastslash;
int len, ret, lastslashidx;
int ret, lastslashidx;
size_t len;
osrc = strdup(orig->src);
if (!osrc) {
SYSERROR("Failed to duplicate \"%s\"", orig->src);
ERROR("Failed to duplicate string \"%s\"", orig->src);
return -22;
}
}
nsrc = strchr(osrc, ':') + 1;
if ((nsrc != osrc + 8) && (nsrc != osrc + 10)) {
free(osrc);
ERROR("Detected \":\" in \"%s\" at wrong position", osrc);
ERROR("Detected \":\" in \"%s\" at wrong position",
osrc);
return -22;
}
}
odelta = strchr(nsrc, ':');
if (!odelta) {
free(osrc);
ERROR("Failed to find \":\" in \"%s\"", nsrc);
ERROR("Failed to find \":\" in \"%s\"", nsrc);
return -22;
}
*odelta = '\0';
odelta++;
ndelta = lxc_string_join("/", (const char *[]){lxcpath, cname, "rootfs", NULL}, false);
if (!ndelta) {
free(osrc);
ERROR("Failed to create new path");
return -ENOMEM;
}
ndelta = must_make_path(lxcpath, cname, "delta0", NULL);
ret = mkdir(ndelta, 0755);
if (ret < 0 && errno != EEXIST) {
free(osrc);
free(ndelta);
SYSERROR("Failed to create \"%s\"", ndelta);
SYSERROR("Failed to create directory \"%s\"", ndelta);
return -1;
}
if (am_unpriv() && chown_mapped_root(ndelta, conf) < 0)
WARN("Failed to update ownership of %s", ndelta);
if (am_unpriv()) {
ret = chown_mapped_root(ndelta, conf);
if (ret < 0)
WARN("Failed to update ownership of %s",
ndelta);
}
/*
* make workdir for overlayfs.v22 or higher (see comment further
* up)
/* Make workdir for overlayfs.v22 or higher (See the comment
* further up.).
*/
lastslash = strrchr(ndelta, '/');
if (!lastslash) {
......@@ -217,22 +251,38 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
ERROR("Failed to allocate memory");
return -1;
}
strncpy(work, ndelta, lastslashidx + 1);
strcpy(work + lastslashidx, "olwork");
strncpy(work + lastslashidx, "olwork", sizeof("olwork") - 1);
work[lastslashidx + sizeof("olwork")] = '\0';
ret = mkdir(work, 0755);
if (ret < 0 && errno != EEXIST) {
free(osrc);
free(ndelta);
free(work);
SYSERROR("Failed to create \"%s\"", ndelta);
SYSERROR("Failed to create directory \"%s\"", ndelta);
return -1;
}
if (am_unpriv() && chown_mapped_root(work, conf) < 0)
WARN("Failed to update ownership of %s", work);
if (am_unpriv()) {
ret = chown_mapped_root(work, conf);
if (ret < 0)
WARN("Failed to update ownership of %s", work);
}
free(work);
len = strlen(nsrc) + strlen(ndelta) + 10;
/* strlen("overlay:") = 8
* +
* strlen(delta)
* +
* :
* +
* strlen(src)
* +
* \0
*/
len = 8 + strlen(ndelta) + 1 + strlen(nsrc) + 1;
new->src = malloc(len);
if (!new->src) {
free(osrc);
......@@ -243,17 +293,16 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
ret = snprintf(new->src, len, "overlay:%s:%s", nsrc, ndelta);
free(osrc);
free(ndelta);
if (ret < 0 || ret >= len) {
if (ret < 0 || (size_t)ret >= len) {
ERROR("Failed to create string");
return -1;
}
}
return ovl_do_rsync(orig, new, conf);
} else {
ERROR("overlay clone of %s container is not yet supported",
orig->type);
/*
* Note, supporting this will require ovl_mount supporting
/* Note, supporting this will require ovl_mount supporting
* mounting of the underlay. No big deal, just needs to be done.
*/
return -1;
......@@ -262,67 +311,86 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
return 0;
}
/*
* to say 'lxc-create -t ubuntu -n o1 -B overlay' means you want
* $lxcpath/$lxcname/rootfs to have the created container, while all
* changes after starting the container are written to
* $lxcpath/$lxcname/delta0
/* To say "lxc-create -t ubuntu -n o1 -B overlay" 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 ovl_create(struct bdev *bdev, const char *dest, const char *n,
struct bdev_specs *specs)
struct bdev_specs *specs)
{
char *delta;
int ret, len = strlen(dest), newlen;
int ret;
size_t len, newlen;
if (len < 8 || strcmp(dest + len - 7, "/rootfs") != 0)
len = strlen(dest);
if (len < 8 || strcmp(dest + len - 7, "/rootfs")) {
ERROR("Failed to detect \"/rootfs\" in \"%s\"", dest);
return -1;
}
if (!(bdev->dest = strdup(dest))) {
ERROR("Out of memory");
bdev->dest = strdup(dest);
if (!bdev->dest) {
ERROR("Failed to duplicate string \"%s\"", dest);
return -1;
}
delta = alloca(strlen(dest) + 1);
strcpy(delta, dest);
strcpy(delta + len - 6, "delta0");
delta = malloc(len + 1);
if (!delta) {
ERROR("Failed to allocate memory");
return -1;
}
strncpy(delta, dest, len);
strncpy(delta + len - 6, "delta0", sizeof("delta0") - 1);
delta[len + sizeof("delta0")] = '\0';
if (mkdir_p(delta, 0755) < 0) {
ERROR("Error creating %s", delta);
ret = mkdir_p(delta, 0755);
if (ret < 0) {
SYSERROR("Failed to create directory \"%s\"", delta);
free(delta);
return -1;
}
// overlay:lower:upper
/* overlay:lower:upper */
newlen = (2 * len) + strlen("overlay:") + 2;
bdev->src = malloc(newlen);
if (!bdev->src) {
ERROR("Out of memory");
ERROR("Failed to allocate memory");
free(delta);
return -1;
}
ret = snprintf(bdev->src, newlen, "overlay:%s:%s", dest, delta);
if (ret < 0 || ret >= newlen)
if (ret < 0 || (size_t)ret >= newlen) {
ERROR("Failed to create string");
free(delta);
return -1;
}
if (mkdir_p(bdev->dest, 0755) < 0) {
ERROR("Error creating %s", bdev->dest);
ret = mkdir_p(bdev->dest, 0755);
if (ret < 0) {
SYSERROR("Failed to create directory \"%s\"", bdev->dest);
free(delta);
return -1;
}
free(delta);
return 0;
}
int ovl_destroy(struct bdev *orig)
{
bool ovl;
bool ovl;
char *upper = orig->src;
ovl = !strncmp(upper, "overlay:", 8);
ovl = !strncmp(upper, "overlay:", 8);
if (!ovl && strncmp(upper, "overlayfs:", 10))
return -22;
if (ovl)
upper += 8;
else
upper += 10;
if (ovl)
upper += 8;
else
upper += 10;
upper = strchr(upper, ':');
if (!upper)
......@@ -348,7 +416,7 @@ int ovl_mount(struct bdev *bdev)
char *tmp, *options, *dup, *lower, *upper;
char *options_work, *work, *lastslash;
int lastslashidx;
int len, len2;
size_t len, len2;
unsigned long mntflags;
char *mntdata;
int ret, ret2;
......@@ -362,53 +430,87 @@ int ovl_mount(struct bdev *bdev)
if (!ovl_name)
ovl_name = ovl_detect_name();
/*
* separately mount it first:
* mount -t overlayfs * -oupperdir=${upper},lowerdir=${lower} lower dest
/* Separately mount it first:
* mount -t overlay * -o upperdir=${upper},lowerdir=${lower} lower dest
*/
dup = alloca(strlen(bdev->src) + 1);
strcpy(dup, bdev->src);
dup = strdup(bdev->src);
if (!dup) {
ERROR("Failed to allocate memory");
return -1;
}
/* support multiple lower layers */
if (!(lower = strstr(dup, ":/")))
return -22;
lower = strstr(dup, ":/");
if (!lower) {
ERROR("Failed to detect \":/\" in string \"%s\"", dup);
free(dup);
return -22;
}
lower++;
upper = lower;
while ((tmp = strstr(++upper, ":/"))) {
upper = tmp;
}
if (--upper == lower)
upper--;
if (upper == lower) {
free(dup);
return -22;
}
*upper = '\0';
upper++;
// if delta doesn't yet exist, create it
if (mkdir_p(upper, 0755) < 0 && errno != EEXIST)
/* if delta doesn't yet exist, create it */
ret = mkdir_p(upper, 0755) < 0;
if (ret < 0 && errno != EEXIST) {
SYSERROR("Failed to create directory \"%s\"", upper);
free(dup);
return -22;
}
/*
* overlayfs.v22 or higher needs workdir option:
/* overlayfs.v22 or higher needs workdir option:
* if upper is
* /var/lib/lxc/c2/delta0
* then workdir is
* /var/lib/lxc/c2/olwork
*/
lastslash = strrchr(upper, '/');
if (!lastslash)
if (!lastslash) {
ERROR("Failed to detect \"/\" in string \"%s\"", upper);
free(dup);
return -22;
}
lastslash++;
lastslashidx = lastslash - upper;
work = alloca(lastslashidx + 7);
strncpy(work, upper, lastslashidx + 7);
strcpy(work + lastslashidx, "olwork");
work = malloc(lastslashidx + 7);
if (!work) {
ERROR("Failed to allocate memory");
free(dup);
return -22;
}
if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
strncpy(work, upper, lastslashidx + 1);
strncpy(work + lastslashidx, "olwork", sizeof("olwork") - 1);
work[lastslashidx + sizeof("olwork")] = '\0';
ret = parse_mntopts(bdev->mntopts, &mntflags, &mntdata);
if (ret < 0) {
ERROR("Failed to parse mount options");
free(mntdata);
free(dup);
free(work);
return -22;
}
if (mkdir_p(work, 0755) < 0 && errno != EEXIST) {
ret = mkdir_p(work, 0755);
if (ret < 0 && errno != EEXIST) {
SYSERROR("Failed to create directory \"%s\"", work);
free(mntdata);
free(dup);
free(work);
return -22;
}
......@@ -419,72 +521,94 @@ int ovl_mount(struct bdev *bdev)
*/
if (mntdata) {
len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=,") + strlen(mntdata) + 1;
len = strlen(lower) + strlen(upper) +
strlen("upperdir=,lowerdir=,") + strlen(mntdata) + 1;
options = alloca(len);
ret = snprintf(options, len, "upperdir=%s,lowerdir=%s,%s", upper, lower, mntdata);
ret = snprintf(options, len, "upperdir=%s,lowerdir=%s,%s",
upper, lower, mntdata);
len2 = strlen(lower) + strlen(upper) + strlen(work)
+ strlen("upperdir=,lowerdir=,workdir=") + strlen(mntdata) + 1;
len2 = strlen(lower) + strlen(upper) + strlen(work) +
strlen("upperdir=,lowerdir=,workdir=") +
strlen(mntdata) + 1;
options_work = alloca(len2);
ret2 = snprintf(options, len2, "upperdir=%s,lowerdir=%s,workdir=%s,%s",
upper, lower, work, mntdata);
ret2 = snprintf(options, len2,
"upperdir=%s,lowerdir=%s,workdir=%s,%s", upper,
lower, work, mntdata);
} else {
len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=") + 1;
len = strlen(lower) + strlen(upper) +
strlen("upperdir=,lowerdir=") + 1;
options = alloca(len);
ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper, lower);
ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper,
lower);
len2 = strlen(lower) + strlen(upper) + strlen(work)
+ strlen("upperdir=,lowerdir=,workdir=") + 1;
len2 = strlen(lower) + strlen(upper) + strlen(work) +
strlen("upperdir=,lowerdir=,workdir=") + 1;
options_work = alloca(len2);
ret2 = snprintf(options_work, len2, "upperdir=%s,lowerdir=%s,workdir=%s",
upper, lower, work);
ret2 = snprintf(options_work, len2,
"upperdir=%s,lowerdir=%s,workdir=%s", upper,
lower, work);
}
if (ret < 0 || ret >= len || ret2 < 0 || ret2 >= len2) {
ERROR("Failed to create string");
free(mntdata);
free(dup);
free(work);
return -1;
}
/* Assume we need a workdir as we are on a overlay version >= v22. */
/* Assume we need a workdir as we are on a overlay version >= v22. */
ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name,
MS_MGC_VAL | mntflags, options_work);
if (ret < 0) {
INFO("Overlay: Error mounting %s onto %s with options %s. "
"Retrying without workdir: %s.",
INFO("Failed to mount \"%s\" on \"%s\" with options \"%s\". "
"Retrying without workdir: %s",
lower, bdev->dest, options_work, strerror(errno));
/* Assume we cannot use a workdir as we are on a version <= v21. */
/* Assume we cannot use a workdir as we are on a version <= v21.
*/
ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name,
MS_MGC_VAL | mntflags, options);
MS_MGC_VAL | mntflags, options);
if (ret < 0)
SYSERROR("Overlay: Error mounting %s onto %s with "
"options %s: %s.",
lower, bdev->dest, options,
strerror(errno));
SYSERROR("Failed to mount \"%s\" on \"%s\" with "
"options \"%s\": %s",
lower, bdev->dest, options, strerror(errno));
else
INFO("Overlay: Mounted %s onto %s with options %s.",
INFO("Mounted \"%s\" on \"%s\" with options \"%s\"",
lower, bdev->dest, options);
} else {
INFO("Overlay: Mounted %s onto %s with options %s.", lower,
INFO("Mounted \"%s\" on \"%s\" with options \"%s\"", lower,
bdev->dest, options_work);
}
free(dup);
free(work);
return ret;
}
int ovl_umount(struct bdev *bdev)
{
int ret;
if (strcmp(bdev->type, "overlay") && strcmp(bdev->type, "overlayfs"))
return -22;
if (!bdev->src || !bdev->dest)
return -22;
return umount(bdev->dest);
ret = umount(bdev->dest);
if (ret < 0)
SYSERROR("Failed to unmount \"%s\"", bdev->dest);
else
TRACE("Unmounted \"%s\"", bdev->dest);
return ret;
}
char *ovl_get_lower(const char *rootfs_path)
{
char *s1;
s1 = strstr(rootfs_path, ":/");
if (!s1)
return NULL;
......@@ -512,7 +636,8 @@ char *ovl_get_rootfs(const char *rootfs_path, size_t *rootfslen)
if (!s1)
return NULL;
if ((s2 = strstr(s1, ":/"))) {
s2 = strstr(s1, ":/");
if (s2) {
s2 = s2 + 1;
if ((s3 = strstr(s2, ":/")))
*s3 = '\0';
......@@ -537,18 +662,12 @@ int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
const char *lxc_name, const char *lxc_path)
{
char lxcpath[MAXPATHLEN];
char *rootfs_path = NULL;
char *rootfsdir = NULL;
char *upperdir = NULL;
char *workdir = NULL;
char **opts = NULL;
char **opts;
int ret;
size_t arrlen, dirlen, i, len, rootfslen;
int fret = -1;
int ret = 0;
size_t arrlen = 0;
size_t dirlen = 0;
size_t i;
size_t len = 0;
size_t rootfslen = 0;
char *rootfs_dir = NULL, *rootfs_path = NULL, *upperdir = NULL,
*workdir = NULL;
/* When rootfs == NULL we have a container without a rootfs. */
if (rootfs && rootfs->path)
......@@ -561,19 +680,22 @@ int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
goto err;
for (i = 0; i < arrlen; i++) {
if (strstr(opts[i], "upperdir=") && (strlen(opts[i]) > (len = strlen("upperdir="))))
if (strstr(opts[i], "upperdir=") &&
(strlen(opts[i]) > (len = strlen("upperdir="))))
upperdir = opts[i] + len;
else if (strstr(opts[i], "workdir=") && (strlen(opts[i]) > (len = strlen("workdir="))))
else if (strstr(opts[i], "workdir=") &&
(strlen(opts[i]) > (len = strlen("workdir="))))
workdir = opts[i] + len;
}
if (rootfs_path) {
ret = snprintf(lxcpath, MAXPATHLEN, "%s/%s", lxc_path, lxc_name);
ret =
snprintf(lxcpath, MAXPATHLEN, "%s/%s", lxc_path, lxc_name);
if (ret < 0 || ret >= MAXPATHLEN)
goto err;
rootfsdir = ovl_get_rootfs(rootfs_path, &rootfslen);
if (!rootfsdir)
rootfs_dir = ovl_get_rootfs(rootfs_path, &rootfslen);
if (!rootfs_dir)
goto err;
dirlen = strlen(lxcpath);
......@@ -588,51 +710,52 @@ int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
if (upperdir) {
if (!rootfs_path)
ret = mkdir_p(upperdir, 0755);
else if ((strncmp(upperdir, lxcpath, dirlen) == 0) && (strncmp(upperdir, rootfsdir, rootfslen) != 0))
else if (!strncmp(upperdir, lxcpath, dirlen) &&
strncmp(upperdir, rootfs_dir, rootfslen))
ret = mkdir_p(upperdir, 0755);
if (ret < 0)
WARN("Failed to create upperdir");
WARN("Failed to create directory \"%s\": %s", upperdir,
strerror(errno));
}
ret = 0;
if (workdir) {
if (!rootfs_path)
ret = mkdir_p(workdir, 0755);
else if ((strncmp(workdir, lxcpath, dirlen) == 0) && (strncmp(workdir, rootfsdir, rootfslen) != 0))
else if (!strncmp(workdir, lxcpath, dirlen) &&
strncmp(workdir, rootfs_dir, rootfslen))
ret = mkdir_p(workdir, 0755);
if (ret < 0)
WARN("Failed to create workdir");
WARN("Failed to create directory \"%s\": %s", workdir,
strerror(errno));
}
fret = 0;
err:
free(rootfsdir);
free(rootfs_dir);
lxc_free_array((void **)opts, free);
return fret;
}
/*
* To be called from lxcapi_clone() in lxccontainer.c: When we clone a container
/* To be called from lxcapi_clone() in lxccontainer.c: When we clone a container
* with overlay lxc.mount.entry entries we need to update absolute paths for
* upper- and workdir. This update is done in two locations:
* lxc_conf->unexpanded_config and lxc_conf->mount_list. Both updates are done
* independent of each other since lxc_conf->mountlist may container more mount
* entries (e.g. from other included files) than lxc_conf->unexpanded_config .
* independent of each other since lxc_conf->mountlist may contain more mount
* entries (e.g. from other included files) than lxc_conf->unexpanded_config.
*/
int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path,
const char *lxc_name, const char *newpath,
const char *newname)
{
char new_upper[MAXPATHLEN];
char new_work[MAXPATHLEN];
char old_upper[MAXPATHLEN];
char old_work[MAXPATHLEN];
char *cleanpath = NULL;
char new_upper[MAXPATHLEN], new_work[MAXPATHLEN], old_upper[MAXPATHLEN],
old_work[MAXPATHLEN];
size_t i;
struct lxc_list *iterator;
char *cleanpath = NULL;
int fret = -1;
int ret = 0;
struct lxc_list *iterator;
const char *ovl_dirs[] = {"br", "upperdir", "workdir"};
cleanpath = strdup(newpath);
......@@ -652,19 +775,20 @@ int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path,
goto err;
}
ret = snprintf(old_work, MAXPATHLEN, "workdir=%s/%s", lxc_path, lxc_name);
ret =
snprintf(old_work, MAXPATHLEN, "workdir=%s/%s", lxc_path, lxc_name);
if (ret < 0 || ret >= MAXPATHLEN)
goto err;
ret = snprintf(new_work, MAXPATHLEN, "workdir=%s/%s", cleanpath, newname);
ret =
snprintf(new_work, MAXPATHLEN, "workdir=%s/%s", cleanpath, newname);
if (ret < 0 || ret >= MAXPATHLEN)
goto err;
lxc_list_for_each(iterator, &lxc_conf->mount_list) {
char *mnt_entry = NULL;
char *new_mnt_entry = NULL;
char *tmp = NULL;
char *tmp_mnt_entry = NULL;
char *mnt_entry = NULL, *new_mnt_entry = NULL, *tmp = NULL,
*tmp_mnt_entry = NULL;
mnt_entry = iterator->elem;
if (strstr(mnt_entry, "overlay"))
......@@ -675,23 +799,28 @@ int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path,
if (!tmp)
continue;
ret = snprintf(old_upper, MAXPATHLEN, "%s=%s/%s", tmp, lxc_path, lxc_name);
ret = snprintf(old_upper, MAXPATHLEN, "%s=%s/%s", tmp, lxc_path,
lxc_name);
if (ret < 0 || ret >= MAXPATHLEN)
goto err;
ret = snprintf(new_upper, MAXPATHLEN, "%s=%s/%s", tmp, cleanpath, newname);
ret = snprintf(new_upper, MAXPATHLEN, "%s=%s/%s", tmp,
cleanpath, newname);
if (ret < 0 || ret >= MAXPATHLEN)
goto err;
if (strstr(mnt_entry, old_upper)) {
tmp_mnt_entry = lxc_string_replace(old_upper, new_upper, mnt_entry);
tmp_mnt_entry =
lxc_string_replace(old_upper, new_upper, mnt_entry);
}
if (strstr(mnt_entry, old_work)) {
if (tmp_mnt_entry)
new_mnt_entry = lxc_string_replace(old_work, new_work, tmp_mnt_entry);
new_mnt_entry = lxc_string_replace(
old_work, new_work, tmp_mnt_entry);
else
new_mnt_entry = lxc_string_replace(old_work, new_work, mnt_entry);
new_mnt_entry = lxc_string_replace(
old_work, new_work, mnt_entry);
}
if (new_mnt_entry) {
......@@ -716,68 +845,24 @@ static int ovl_remount_on_enodev(const char *lower, const char *target,
const char *name, unsigned long mountflags,
const void *options)
{
int ret;
ret = mount(lower, target, ovl_name, MS_MGC_VAL | mountflags, options);
if (ret < 0 && errno == ENODEV) /* Try other module name. */
int ret;
ret = mount(lower, target, ovl_name, MS_MGC_VAL | mountflags, options);
if (ret < 0 && errno == ENODEV) /* Try other module name. */
ret = mount(lower, target,
ovl_name == ovl_version[0] ? ovl_version[1]
: ovl_version[0],
MS_MGC_VAL | mountflags, options);
return ret;
}
static int ovl_rsync(struct rsync_data *data)
{
int ret;
if (setgid(0) < 0) {
ERROR("Failed to setgid to 0");
return -1;
}
if (setgroups(0, NULL) < 0)
WARN("Failed to clear groups");
if (setuid(0) < 0) {
ERROR("Failed to setuid to 0");
return -1;
}
if (unshare(CLONE_NEWNS) < 0) {
SYSERROR("Unable to unshare mounts ns");
return -1;
}
if (detect_shared_rootfs()) {
if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) {
SYSERROR("Failed to make / rslave");
ERROR("Continuing...");
}
}
if (ovl_mount(data->orig) < 0) {
ERROR("Failed mounting original container fs");
return -1;
}
if (ovl_mount(data->new) < 0) {
ERROR("Failed mounting new container fs");
return -1;
}
ret = do_rsync(data->orig->dest, data->new->dest);
ovl_umount(data->new);
ovl_umount(data->orig);
if (ret < 0) {
ERROR("rsyncing %s to %s", data->orig->dest, data->new->dest);
return -1;
}
return 0;
return ret;
}
static char *ovl_detect_name(void)
{
FILE *f;
char *v = ovl_version[0];
char *line = NULL;
size_t len = 0;
FILE *f = fopen("/proc/filesystems", "r");
f = fopen("/proc/filesystems", "r");
if (!f)
return v;
......@@ -793,27 +878,28 @@ static char *ovl_detect_name(void)
return v;
}
static int ovl_do_rsync(struct bdev *orig, struct bdev *new, struct lxc_conf *conf)
static int ovl_do_rsync(struct bdev *orig, struct bdev *new,
struct lxc_conf *conf)
{
int ret = -1;
struct rsync_data rdata;
struct rsync_data rdata = {0, 0};
char cmd_output[MAXPATHLEN] = {0};
rdata.orig = orig;
rdata.new = new;
if (am_unpriv())
ret = userns_exec_1(conf, ovl_rsync_wrapper, &rdata,
"ovl_rsync_wrapper");
else
ret = ovl_rsync(&rdata);
if (ret)
ERROR("copying overlay delta");
if (am_unpriv()) {
ret = userns_exec_1(conf, lxc_rsync_exec_wrapper, &rdata,
"lxc_rsync_exec_wrapper");
if (ret < 0)
ERROR("Failed to rsync from \"%s\" into \"%s\"",
orig->dest, new->dest);
} else {
ret = run_command(cmd_output, sizeof(cmd_output),
lxc_rsync_exec_wrapper, (void *)&rdata);
if (ret < 0)
ERROR("Failed to rsync from \"%s\" into \"%s\": %s",
orig->dest, new->dest, cmd_output);
}
return ret;
}
static int ovl_rsync_wrapper(void *data)
{
struct rsync_data *arg = data;
return ovl_rsync(arg);
}
......@@ -1263,11 +1263,45 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
if (strcmp(bdev->type, "dir") && strcmp(bdev->type, "btrfs")) {
if (geteuid() != 0) {
ERROR("non-root users can only create btrfs and directory-backed containers");
exit(1);
exit(EXIT_FAILURE);
}
if (bdev->ops->mount(bdev) < 0) {
ERROR("Error mounting rootfs");
exit(1);
if (!strcmp(bdev->type, "overlay") || !strcmp(bdev->type, "overlayfs")) {
/* If we create an overlay container we need to
* rsync the contents into
* <container-path>/<container-name>/rootfs.
* However, the overlay mount function will
* mount will mount
* <container-path>/<container-name>/delta0
* over
* <container-path>/<container-name>/rootfs
* which means we would rsync the rootfs into
* the delta directory. That doesn't make sense
* since the delta directory only exists to
* record the differences to
* <container-path>/<container-name>/rootfs. So
* let's simply bind-mount here and then rsync
* directly into
* <container-path>/<container-name>/rootfs.
*/
char *src;
src = ovl_get_rootfs(bdev->src, &(size_t){0});
if (!src) {
ERROR("Failed to get rootfs");
exit(EXIT_FAILURE);
}
ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC, NULL);
if (ret < 0) {
ERROR("Failed to mount rootfs");
return -1;
}
} else {
if (bdev->ops->mount(bdev) < 0) {
ERROR("Failed to mount rootfs");
exit(EXIT_FAILURE);
}
}
} else { // TODO come up with a better way here!
char *src;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment