Commit a14bf84f by Serge Hallyn

Merge pull request #724 from brauner/2015-12-12/split_bdev_into_modules

split bdev into modules
parents fbc617e8 5c484f79
...@@ -6,7 +6,9 @@ pkginclude_HEADERS = \ ...@@ -6,7 +6,9 @@ pkginclude_HEADERS = \
noinst_HEADERS = \ noinst_HEADERS = \
arguments.h \ arguments.h \
attach.h \ attach.h \
bdev.h \ bdev/bdev.h \
bdev/lxc-btrfs.h \
bdev/overlay.h \
caps.h \ caps.h \
cgroup.h \ cgroup.h \
conf.h \ conf.h \
...@@ -16,7 +18,6 @@ noinst_HEADERS = \ ...@@ -16,7 +18,6 @@ noinst_HEADERS = \
list.h \ list.h \
log.h \ log.h \
lxc.h \ lxc.h \
lxc-btrfs.h \
lxclock.h \ lxclock.h \
monitor.h \ monitor.h \
namespace.h \ namespace.h \
...@@ -60,7 +61,7 @@ endif ...@@ -60,7 +61,7 @@ endif
liblxc_so_SOURCES = \ liblxc_so_SOURCES = \
arguments.c arguments.h \ arguments.c arguments.h \
bdev.c bdev.h lxc-btrfs.h \ bdev/bdev.c bdev/bdev.h bdev/overlay.c bdev/overlay.h bdev/lxc-btrfs.h \
commands.c commands.h \ commands.c commands.h \
start.c start.h \ start.c start.h \
execute.c \ execute.c \
......
...@@ -27,33 +27,38 @@ ...@@ -27,33 +27,38 @@
* I'm doing by calling out to userspace should sometimes be done through * I'm doing by calling out to userspace should sometimes be done through
* libraries like liblvm2 * libraries like liblvm2
*/ */
#define _GNU_SOURCE #define _GNU_SOURCE
#include <stdio.h> #include <dirent.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/types.h>
#include <grp.h>
#include <unistd.h>
#include <errno.h> #include <errno.h>
#include <sched.h> #include <fcntl.h>
#include <sys/mount.h> #include <grp.h>
#include <sys/wait.h> #include <inttypes.h>
#include <libgen.h> #include <libgen.h>
#include <sched.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <linux/loop.h> #include <linux/loop.h>
#include <dirent.h> #include <sys/mount.h>
#include <sys/prctl.h> #include <sys/prctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "lxc.h" #include "bdev.h"
#include "config.h" #include "config.h"
#include "conf.h" #include "conf.h"
#include "bdev.h"
#include "log.h"
#include "error.h" #include "error.h"
#include "utils.h" #include "log.h"
#include "namespace.h" #include "lxc.h"
#include "parse.h"
#include "lxclock.h" #include "lxclock.h"
#include "lxc-btrfs.h" #include "lxc-btrfs.h"
#include "namespace.h"
#include "overlay.h" /* overlay */
#include "parse.h"
#include "utils.h"
#ifndef BLKGETSIZE64 #ifndef BLKGETSIZE64
#define BLKGETSIZE64 _IOR(0x12,114,size_t) #define BLKGETSIZE64 _IOR(0x12,114,size_t)
...@@ -72,17 +77,13 @@ ...@@ -72,17 +77,13 @@
lxc_log_define(bdev, lxc); lxc_log_define(bdev, lxc);
struct ovl_rsync_data {
struct bdev *orig;
struct bdev *new;
};
struct rsync_data_char { struct rsync_data_char {
char *src; char *src;
char *dest; char *dest;
}; };
static int do_rsync(const char *src, const char *dest) /* the bulk of this needs to become a common helper */
int do_rsync(const char *src, const char *dest)
{ {
// call out to rsync // call out to rsync
pid_t pid; pid_t pid;
...@@ -107,6 +108,48 @@ static int do_rsync(const char *src, const char *dest) ...@@ -107,6 +108,48 @@ static int do_rsync(const char *src, const char *dest)
exit(1); exit(1);
} }
/* the bulk of this needs to become a common helper */
char *dir_new_path(char *src, const char *oldname, const char *name,
const char *oldpath, const char *lxcpath)
{
char *ret, *p, *p2;
int l1, l2, nlen;
nlen = strlen(src) + 1;
l1 = strlen(oldpath);
p = src;
/* if src starts with oldpath, look for oldname only after
* that path */
if (strncmp(src, oldpath, l1) == 0) {
p += l1;
nlen += (strlen(lxcpath) - l1);
}
l2 = strlen(oldname);
while ((p = strstr(p, oldname)) != NULL) {
p += l2;
nlen += strlen(name) - l2;
}
ret = malloc(nlen);
if (!ret)
return NULL;
p = ret;
if (strncmp(src, oldpath, l1) == 0) {
p += sprintf(p, "%s", lxcpath);
src += l1;
}
while ((p2 = strstr(src, oldname)) != NULL) {
strncpy(p, src, p2-src); // copy text up to oldname
p += p2-src; // move target pointer (p)
p += sprintf(p, "%s", name); // print new name in place of oldname
src = p2 + l2; // move src to end of oldname
}
sprintf(p, "%s", src); // copy the rest of src
return ret;
}
/* /*
* return block size of dev->src in units of bytes * return block size of dev->src in units of bytes
*/ */
...@@ -404,48 +447,6 @@ static int dir_umount(struct bdev *bdev) ...@@ -404,48 +447,6 @@ static int dir_umount(struct bdev *bdev)
return umount(bdev->dest); return umount(bdev->dest);
} }
/* the bulk of this needs to become a common helper */
static char *dir_new_path(char *src, const char *oldname, const char *name,
const char *oldpath, const char *lxcpath)
{
char *ret, *p, *p2;
int l1, l2, nlen;
nlen = strlen(src) + 1;
l1 = strlen(oldpath);
p = src;
/* if src starts with oldpath, look for oldname only after
* that path */
if (strncmp(src, oldpath, l1) == 0) {
p += l1;
nlen += (strlen(lxcpath) - l1);
}
l2 = strlen(oldname);
while ((p = strstr(p, oldname)) != NULL) {
p += l2;
nlen += strlen(name) - l2;
}
ret = malloc(nlen);
if (!ret)
return NULL;
p = ret;
if (strncmp(src, oldpath, l1) == 0) {
p += sprintf(p, "%s", lxcpath);
src += l1;
}
while ((p2 = strstr(src, oldname)) != NULL) {
strncpy(p, src, p2-src); // copy text up to oldname
p += p2-src; // move target pointer (p)
p += sprintf(p, "%s", name); // print new name in place of oldname
src = p2 + l2; // move src to end of oldname
}
sprintf(p, "%s", src); // copy the rest of src
return ret;
}
/* /*
* for a simple directory bind mount, we substitute the old container * for a simple directory bind mount, we substitute the old container
* name and paths for the new * name and paths for the new
...@@ -2321,158 +2322,6 @@ static const struct bdev_ops loop_ops = { ...@@ -2321,158 +2322,6 @@ static const struct bdev_ops loop_ops = {
.can_backup = true, .can_backup = true,
}; };
//
// overlayfs ops
//
static int overlayfs_detect(const char *path)
{
if (strncmp(path, "overlayfs:", 10) == 0)
return 1; // take their word for it
return 0;
}
static char *overlayfs_name;
static char *detect_overlayfs_name(void)
{
char *v = "overlayfs";
char *line = NULL;
size_t len = 0;
FILE *f = fopen("/proc/filesystems", "r");
if (!f)
return v;
while (getline(&line, &len, f) != -1) {
if (strcmp(line, "nodev\toverlay\n") == 0) {
v = "overlay";
break;
}
}
fclose(f);
free(line);
return v;
}
//
// XXXXXXX plain directory bind mount ops
//
static int overlayfs_mount(struct bdev *bdev)
{
char *options, *dup, *lower, *upper;
char *options_work, *work, *lastslash;
int lastslashidx;
int len, len2;
unsigned long mntflags;
char *mntdata;
int ret, ret2;
if (strcmp(bdev->type, "overlayfs"))
return -22;
if (!bdev->src || !bdev->dest)
return -22;
if (!overlayfs_name)
overlayfs_name = detect_overlayfs_name();
// separately mount it first
// mount -t overlayfs -oupperdir=${upper},lowerdir=${lower} 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 delta doesn't yet exist, create it
if (mkdir_p(upper, 0755) < 0 && errno != EEXIST)
return -22;
// 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)
return -22;
lastslash++;
lastslashidx = lastslash - upper;
work = alloca(lastslashidx + 7);
strncpy(work, upper, lastslashidx+7);
strcpy(work+lastslashidx, "olwork");
if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
free(mntdata);
return -22;
}
if (mkdir_p(work, 0755) < 0 && errno != EEXIST) {
free(mntdata);
return -22;
}
// TODO We should check whether bdev->src is a blockdev, and if so
// but for now, only support overlays of a basic directory
if (mntdata) {
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);
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);
}
else {
len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=") + 1;
options = alloca(len);
ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper, lower);
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);
}
if (ret < 0 || ret >= len || ret2 < 0 || ret2 >= len2) {
free(mntdata);
return -1;
}
// mount without workdir option for overlayfs before v21
ret = mount(lower, bdev->dest, overlayfs_name, MS_MGC_VAL | mntflags, options);
if (ret < 0) {
INFO("overlayfs: error mounting %s onto %s options %s. retry with workdir",
lower, bdev->dest, options);
// retry with workdir option for overlayfs v22 and higher
ret = mount(lower, bdev->dest, overlayfs_name, MS_MGC_VAL | mntflags, options_work);
if (ret < 0)
SYSERROR("overlayfs: error mounting %s onto %s options %s",
lower, bdev->dest, options_work);
else
INFO("overlayfs: mounted %s onto %s options %s",
lower, bdev->dest, options_work);
}
else
INFO("overlayfs: mounted %s onto %s options %s",
lower, bdev->dest, options);
return ret;
}
static int overlayfs_umount(struct bdev *bdev)
{
if (strcmp(bdev->type, "overlayfs"))
return -22;
if (!bdev->src || !bdev->dest)
return -22;
return umount(bdev->dest);
}
static int rsync_delta(struct rsync_data_char *data) static int rsync_delta(struct rsync_data_char *data)
{ {
if (setgid(0) < 0) { if (setgid(0) < 0) {
...@@ -2499,303 +2348,14 @@ static int rsync_delta_wrapper(void *data) ...@@ -2499,303 +2348,14 @@ static int rsync_delta_wrapper(void *data)
return rsync_delta(arg); return rsync_delta(arg);
} }
static int ovl_rsync(struct ovl_rsync_data *data) /* overlay */
{ static const struct bdev_ops ovl_ops = {
int ret; .detect = &ovl_detect,
.mount = &ovl_mount,
if (setgid(0) < 0) { .umount = &ovl_umount,
ERROR("Failed to setgid to 0"); .clone_paths = &ovl_clonepaths,
return -1; .destroy = &ovl_destroy,
} .create = &ovl_create,
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 (overlayfs_mount(data->orig) < 0) {
ERROR("Failed mounting original container fs");
return -1;
}
if (overlayfs_mount(data->new) < 0) {
ERROR("Failed mounting new container fs");
return -1;
}
ret = do_rsync(data->orig->dest, data->new->dest);
overlayfs_umount(data->new);
overlayfs_umount(data->orig);
if (ret < 0) {
ERROR("rsyncing %s to %s", data->orig->dest, data->new->dest);
return -1;
}
return 0;
}
static int ovl_rsync_wrapper(void *data)
{
struct ovl_rsync_data *arg = data;
return ovl_rsync(arg);
}
static int ovl_do_rsync(struct bdev *orig, struct bdev *new, struct lxc_conf *conf)
{
int ret = -1;
struct ovl_rsync_data rdata;
rdata.orig = orig;
rdata.new = new;
if (am_unpriv())
ret = userns_exec_1(conf, ovl_rsync_wrapper, &rdata);
else
ret = ovl_rsync(&rdata);
if (ret)
ERROR("copying overlayfs delta");
return ret;
}
static int overlayfs_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("overlayfs 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;
char *work;
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);
// make workdir for overlayfs.v22 or higher
// workdir is /var/lib/lxc/c2/olwork
// it is used to prepare files before atomically swithing with destination,
// and needs to be on the same filesystem as upperdir,
// so it's OK for it to be empty.
work = malloc(lastslashidx + 7);
if (!work) {
free(delta);
return -1;
}
strncpy(work, new->dest, lastslashidx+1);
strcpy(work+lastslashidx, "olwork");
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);
free(work);
// the src will be 'overlayfs: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, "overlayfs:%s:%s", orig->src, delta);
free(delta);
if (ret < 0 || ret >= len)
return -ENOMEM;
} else if (strcmp(orig->type, "overlayfs") == 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, *work;
char *lastslash;
int len, ret, lastslashidx;
if (!(osrc = strdup(orig->src)))
return -22;
nsrc = strchr(osrc, ':') + 1;
if (nsrc != osrc + 10 || (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);
// make workdir for overlayfs.v22 or higher
// for details, see above.
lastslash = strrchr(ndelta, '/');
if (!lastslash)
return -1;
lastslash++;
lastslashidx = lastslash - ndelta;
work = malloc(lastslashidx + 7);
if (!work)
return -1;
strncpy(work, ndelta, lastslashidx+1);
strcpy(work+lastslashidx, "olwork");
if ((mkdir(work, 0755) < 0) && errno != EEXIST) {
SYSERROR("error: mkdir %s", work);
free(work);
return -1;
}
if (am_unpriv() && chown_mapped_root(work, conf) < 0)
WARN("Failed to update ownership of %s", work);
free(work);
len = strlen(nsrc) + strlen(ndelta) + 12;
new->src = malloc(len);
if (!new->src) {
free(osrc);
free(ndelta);
return -ENOMEM;
}
ret = snprintf(new->src, len, "overlayfs:%s:%s", nsrc, ndelta);
free(osrc);
free(ndelta);
if (ret < 0 || ret >= len)
return -ENOMEM;
return ovl_do_rsync(orig, new, conf);
} else {
ERROR("overlayfs clone of %s container is not yet supported",
orig->type);
// Note, supporting this will require overlayfs_mount supporting
// mounting of the underlay. No big deal, just needs to be done.
return -1;
}
return 0;
}
static int overlayfs_destroy(struct bdev *orig)
{
char *upper;
if (strncmp(orig->src, "overlayfs:", 10) != 0)
return -22;
upper = strchr(orig->src + 10, ':');
if (!upper)
return -22;
upper++;
return lxc_rmdir_onedev(upper, NULL);
}
/*
* to say 'lxc-create -t ubuntu -n o1 -B overlayfs' 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 overlayfs_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;
}
/* overlayfs:lower:upper */
newlen = (2 * len) + strlen("overlayfs:") + 2;
bdev->src = malloc(newlen);
if (!bdev->src) {
ERROR("Out of memory");
return -1;
}
ret = snprintf(bdev->src, newlen, "overlayfs:%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 overlayfs_ops = {
.detect = &overlayfs_detect,
.mount = &overlayfs_mount,
.umount = &overlayfs_umount,
.clone_paths = &overlayfs_clonepaths,
.destroy = &overlayfs_destroy,
.create = &overlayfs_create,
.can_snapshot = true, .can_snapshot = true,
.can_backup = true, .can_backup = true,
}; };
...@@ -3403,7 +2963,7 @@ static const struct bdev_type bdevs[] = { ...@@ -3403,7 +2963,7 @@ static const struct bdev_type bdevs[] = {
{.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 = "aufs", .ops = &aufs_ops,},
{.name = "overlayfs", .ops = &overlayfs_ops,}, {.name = "overlayfs", .ops = &ovl_ops,},
{.name = "loop", .ops = &loop_ops,}, {.name = "loop", .ops = &loop_ops,},
{.name = "nbd", .ops = &nbd_ops,}, {.name = "nbd", .ops = &nbd_ops,},
}; };
...@@ -3818,14 +3378,6 @@ struct bdev *bdev_create(const char *dest, const char *type, ...@@ -3818,14 +3378,6 @@ 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 *overlay_getlower(char *p)
{
char *p1 = strchr(p, ':');
if (p1)
*p1 = '\0';
return p;
}
bool rootfs_is_blockdev(struct lxc_conf *conf) bool rootfs_is_blockdev(struct lxc_conf *conf)
{ {
const struct bdev_type *q; const struct bdev_type *q;
......
...@@ -27,11 +27,11 @@ ...@@ -27,11 +27,11 @@
* aufs, dir, raw, btrfs, overlayfs, aufs, lvm, loop, zfs, nbd (qcow2, raw, vdi, qed) * aufs, dir, raw, btrfs, overlayfs, aufs, lvm, loop, zfs, nbd (qcow2, raw, vdi, qed)
*/ */
#include "config.h"
#include <stdint.h> #include <stdint.h>
#include <lxc/lxccontainer.h> #include <lxc/lxccontainer.h>
#include <sys/mount.h> #include <sys/mount.h>
#include "config.h"
/* define constants if the kernel/glibc headers don't define them */ /* define constants if the kernel/glibc headers don't define them */
#ifndef MS_DIRSYNC #ifndef MS_DIRSYNC
...@@ -97,8 +97,6 @@ struct bdev { ...@@ -97,8 +97,6 @@ struct bdev {
int nbd_idx; int nbd_idx;
}; };
char *overlay_getlower(char *p);
bool bdev_is_dir(struct lxc_conf *conf, const char *path); bool bdev_is_dir(struct lxc_conf *conf, const char *path);
bool bdev_can_backup(struct lxc_conf *conf); bool bdev_can_backup(struct lxc_conf *conf);
......
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bdev.h"
#include "conf.h"
#include "confile.h"
#include "log.h"
#include "lxccontainer.h"
#include "overlay.h"
#include "utils.h"
lxc_log_define(overlay, lxc);
static char *ovl_name;
struct ovl_rsync_data {
struct bdev *orig;
struct bdev *new;
};
/* defined in lxccontainer.c: needs to become common helper */
extern int do_rsync(const char *src, const char *dest);
/* defined in lxccontainer.c: needs to become common helper */
extern char *dir_new_path(char *src, const char *oldname, const char *name,
const char *oldpath, const char *lxcpath);
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 ovl_rsync_data *data);
static int ovl_rsync_wrapper(void *data);
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)
{
if (!snap) {
ERROR("overlayfs 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;
char *work;
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);
/*
* 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
* switched to the overlay destination. Workdirs need to be on
* the same filesystem as the upperdir so it's OK for it to be
* empty.
*/
work = malloc(lastslashidx + 7);
if (!work) {
free(delta);
return -1;
}
strncpy(work, new->dest, lastslashidx + 1);
strcpy(work + lastslashidx, "olwork");
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);
free(work);
// the src will be 'overlayfs: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, "overlayfs:%s:%s", orig->src, delta);
free(delta);
if (ret < 0 || ret >= len)
return -ENOMEM;
} else if (strcmp(orig->type, "overlayfs") == 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, *work;
char *lastslash;
int len, ret, lastslashidx;
if (!(osrc = strdup(orig->src)))
return -22;
nsrc = strchr(osrc, ':') + 1;
if (nsrc != osrc + 10 || (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);
/*
* make workdir for overlayfs.v22 or higher (see comment further
* up)
*/
lastslash = strrchr(ndelta, '/');
if (!lastslash)
return -1;
lastslash++;
lastslashidx = lastslash - ndelta;
work = malloc(lastslashidx + 7);
if (!work)
return -1;
strncpy(work, ndelta, lastslashidx + 1);
strcpy(work + lastslashidx, "olwork");
if ((mkdir(work, 0755) < 0) && errno != EEXIST) {
SYSERROR("error: mkdir %s", work);
free(work);
return -1;
}
if (am_unpriv() && chown_mapped_root(work, conf) < 0)
WARN("Failed to update ownership of %s", work);
free(work);
len = strlen(nsrc) + strlen(ndelta) + 12;
new->src = malloc(len);
if (!new->src) {
free(osrc);
free(ndelta);
return -ENOMEM;
}
ret = snprintf(new->src, len, "overlayfs:%s:%s", nsrc, ndelta);
free(osrc);
free(ndelta);
if (ret < 0 || ret >= len)
return -ENOMEM;
return ovl_do_rsync(orig, new, conf);
} else {
ERROR("overlayfs clone of %s container is not yet supported",
orig->type);
/*
* Note, supporting this will require ovl_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 overlayfs' 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)
{
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;
}
// overlayfs:lower:upper
newlen = (2 * len) + strlen("overlayfs:") + 2;
bdev->src = malloc(newlen);
if (!bdev->src) {
ERROR("Out of memory");
return -1;
}
ret = snprintf(bdev->src, newlen, "overlayfs:%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 ovl_destroy(struct bdev *orig)
{
char *upper;
if (strncmp(orig->src, "overlayfs:", 10) != 0)
return -22;
upper = strchr(orig->src + 10, ':');
if (!upper)
return -22;
upper++;
return lxc_rmdir_onedev(upper, NULL);
}
int ovl_detect(const char *path)
{
if (strncmp(path, "overlayfs:", 10) == 0)
return 1; // take their word for it
return 0;
}
char *ovl_getlower(char *p)
{
char *p1 = strchr(p, ':');
if (p1)
*p1 = '\0';
return p;
}
int ovl_mount(struct bdev *bdev)
{
char *options, *dup, *lower, *upper;
char *options_work, *work, *lastslash;
int lastslashidx;
int len, len2;
unsigned long mntflags;
char *mntdata;
int ret, ret2;
if (strcmp(bdev->type, "overlayfs"))
return -22;
if (!bdev->src || !bdev->dest)
return -22;
if (!ovl_name)
ovl_name = ovl_detect_name();
/*
* separately mount it first:
* mount -t overlayfs * -oupperdir=${upper},lowerdir=${lower} 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 delta doesn't yet exist, create it
if (mkdir_p(upper, 0755) < 0 && errno != EEXIST)
return -22;
/*
* 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)
return -22;
lastslash++;
lastslashidx = lastslash - upper;
work = alloca(lastslashidx + 7);
strncpy(work, upper, lastslashidx + 7);
strcpy(work + lastslashidx, "olwork");
if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
free(mntdata);
return -22;
}
if (mkdir_p(work, 0755) < 0 && errno != EEXIST) {
free(mntdata);
return -22;
}
/*
* TODO:
* We should check whether bdev->src is a blockdev but for now only
* support overlays of a basic directory
*/
if (mntdata) {
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);
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);
} else {
len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=") + 1;
options = alloca(len);
ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper, lower);
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);
}
if (ret < 0 || ret >= len || ret2 < 0 || ret2 >= len2) {
free(mntdata);
return -1;
}
// mount without workdir option for overlayfs before v21
ret = mount(lower, bdev->dest, ovl_name, MS_MGC_VAL | mntflags, options);
if (ret < 0) {
INFO("overlayfs: error mounting %s onto %s options %s. retry with workdir",
lower, bdev->dest, options);
// retry with workdir option for overlayfs v22 and higher
ret = mount(lower, bdev->dest, ovl_name, MS_MGC_VAL | mntflags, options_work);
if (ret < 0)
SYSERROR("overlayfs: error mounting %s onto %s options %s",
lower, bdev->dest, options_work);
else
INFO("overlayfs: mounted %s onto %s options %s",
lower, bdev->dest, options_work);
} else {
INFO("overlayfs: mounted %s onto %s options %s",
lower, bdev->dest, options);
}
return ret;
}
int ovl_umount(struct bdev *bdev)
{
if (strcmp(bdev->type, "overlayfs"))
return -22;
if (!bdev->src || !bdev->dest)
return -22;
return umount(bdev->dest);
}
char *ovl_get_rootfs(const char *rootfs_path, size_t *rootfslen)
{
char *rootfsdir = NULL;
char *s1 = NULL;
char *s2 = NULL;
char *s3 = NULL;
if (!rootfs_path || !rootfslen)
return NULL;
s1 = strdup(rootfs_path);
if (!s1)
return NULL;
if ((s2 = strstr(s1, ":/"))) {
s2 = s2 + 1;
if ((s3 = strstr(s2, ":/")))
*s3 = '\0';
rootfsdir = strdup(s2);
if (!rootfsdir) {
free(s1);
return NULL;
}
}
if (!rootfsdir)
rootfsdir = s1;
else
free(s1);
*rootfslen = strlen(rootfsdir);
return rootfsdir;
}
int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
const char *lxc_name, const char *lxc_path)
{
char lxcpath[MAXPATHLEN];
char *rootfsdir = NULL;
char *upperdir = NULL;
char *workdir = NULL;
char **opts = NULL;
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;
if (!rootfs->path || !lxc_name || !lxc_path)
goto err;
opts = lxc_string_split(mntent->mnt_opts, ',');
if (opts)
arrlen = lxc_array_len((void **)opts);
else
goto err;
for (i = 0; i < arrlen; i++) {
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="))))
workdir = opts[i] + len;
}
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)
goto err;
dirlen = strlen(lxcpath);
/*
* We neither allow users to create upperdirs and workdirs outside the
* containerdir nor inside the rootfs. The latter might be debatable.
*/
if (upperdir)
if ((strncmp(upperdir, lxcpath, dirlen) == 0) && (strncmp(upperdir, rootfsdir, rootfslen) != 0))
if (mkdir_p(upperdir, 0755) < 0) {
WARN("Failed to create upperdir");
}
if (workdir)
if ((strncmp(workdir, lxcpath, dirlen) == 0) && (strncmp(workdir, rootfsdir, rootfslen) != 0))
if (mkdir_p(workdir, 0755) < 0) {
WARN("Failed to create workdir");
}
fret = 0;
err:
free(rootfsdir);
lxc_free_array((void **)opts, free);
return fret;
}
/*
* 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 .
*/
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;
int i;
int fret = -1;
int ret = 0;
struct lxc_list *iterator;
const char *ovl_dirs[] = {"br", "upperdir", "workdir"};
cleanpath = strdup(newpath);
if (!cleanpath)
goto err;
remove_trailing_slashes(cleanpath);
/*
* We have to update lxc_conf->unexpanded_config separately from
* lxc_conf->mount_list.
*/
for (i = 0; i < sizeof(ovl_dirs) / sizeof(ovl_dirs[0]); i++) {
if (!clone_update_unexp_ovl_paths(lxc_conf, lxc_path, newpath,
lxc_name, newname,
ovl_dirs[i]))
goto err;
}
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);
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;
mnt_entry = iterator->elem;
if (strstr(mnt_entry, "overlay"))
tmp = "upperdir";
else if (strstr(mnt_entry, "aufs"))
tmp = "br";
if (!tmp)
continue;
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);
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);
}
if (strstr(mnt_entry, old_work)) {
if (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);
}
if (new_mnt_entry) {
free(iterator->elem);
iterator->elem = strdup(new_mnt_entry);
} else if (tmp_mnt_entry) {
free(iterator->elem);
iterator->elem = strdup(tmp_mnt_entry);
}
free(new_mnt_entry);
free(tmp_mnt_entry);
}
fret = 0;
err:
free(cleanpath);
return fret;
}
static int ovl_rsync(struct ovl_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;
}
static char *ovl_detect_name(void)
{
char *v = "overlayfs";
char *line = NULL;
size_t len = 0;
FILE *f = fopen("/proc/filesystems", "r");
if (!f)
return v;
while (getline(&line, &len, f) != -1) {
if (strcmp(line, "nodev\toverlay\n") == 0) {
v = "overlay";
break;
}
}
fclose(f);
free(line);
return v;
}
static int ovl_do_rsync(struct bdev *orig, struct bdev *new, struct lxc_conf *conf)
{
int ret = -1;
struct ovl_rsync_data rdata;
rdata.orig = orig;
rdata.new = new;
if (am_unpriv())
ret = userns_exec_1(conf, ovl_rsync_wrapper, &rdata);
else
ret = ovl_rsync(&rdata);
if (ret)
ERROR("copying overlayfs delta");
return ret;
}
static int ovl_rsync_wrapper(void *data)
{
struct ovl_rsync_data *arg = data;
return ovl_rsync(arg);
}
/*
* 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_OVERLAY_H
#define __LXC_OVERLAY_H
#include <grp.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#if IS_BIONIC
#include <../include/lxcmntent.h>
#else
#include <mntent.h>
#endif
/* defined in bdev.h */
struct bdev;
/* defined in lxccontainer.h */
struct bdev_specs;
/* defined conf.h */
struct lxc_conf;
/* defined in conf.h */
struct lxc_rootfs;
/*
* Functions associated with an overlay bdev struct.
*/
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);
int ovl_create(struct bdev *bdev, const char *dest, const char *n,
struct bdev_specs *specs);
int ovl_destroy(struct bdev *orig);
int ovl_detect(const char *path);
int ovl_mount(struct bdev *bdev);
int ovl_umount(struct bdev *bdev);
/*
* 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 .
*/
int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path,
const char *lxc_name, const char *newpath,
const char *newname);
/*
* To be called from functions in lxccontainer.c: Get lower directory for
* overlay rootfs.
*/
char *ovl_getlower(char *p);
/*
* Get rootfs path for overlay backed containers. Allocated memory must be freed
* by caller.
*/
char *ovl_get_rootfs(const char *rootfs_path, size_t *rootfslen);
/*
* Create upper- and workdirs for overlay mounts.
*/
int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
const char *lxc_name, const char *lxc_path);
#endif /* __LXC_OVERLAY_H */
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
#include "list.h" #include "list.h"
#include "conf.h" #include "conf.h"
#include "utils.h" #include "utils.h"
#include "bdev.h" #include "bdev/bdev.h"
#include "log.h" #include "log.h"
#include "cgroup.h" #include "cgroup.h"
#include "start.h" #include "start.h"
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
#include "list.h" #include "list.h"
#include "conf.h" #include "conf.h"
#include "utils.h" #include "utils.h"
#include "bdev.h" #include "bdev/bdev.h"
#include "log.h" #include "log.h"
#include "cgroup.h" #include "cgroup.h"
#include "start.h" #include "start.h"
......
...@@ -71,7 +71,8 @@ ...@@ -71,7 +71,8 @@
#include "conf.h" #include "conf.h"
#include "log.h" #include "log.h"
#include "caps.h" /* for lxc_caps_last_cap() */ #include "caps.h" /* for lxc_caps_last_cap() */
#include "bdev.h" #include "bdev/bdev.h"
#include "bdev/overlay.h"
#include "cgroup.h" #include "cgroup.h"
#include "lxclock.h" #include "lxclock.h"
#include "namespace.h" #include "namespace.h"
...@@ -1815,107 +1816,6 @@ static void cull_mntent_opt(struct mntent *mntent) ...@@ -1815,107 +1816,6 @@ static void cull_mntent_opt(struct mntent *mntent)
} }
} }
static char *ovl_get_rootfs_dir(const char *rootfs_path, size_t *rootfslen)
{
char *rootfsdir = NULL;
char *s1 = NULL;
char *s2 = NULL;
char *s3 = NULL;
if (!rootfs_path || !rootfslen)
return NULL;
s1 = strdup(rootfs_path);
if (!s1)
return NULL;
if ((s2 = strstr(s1, ":/"))) {
s2 = s2 + 1;
if ((s3 = strstr(s2, ":/")))
*s3 = '\0';
rootfsdir = strdup(s2);
if (!rootfsdir) {
free(s1);
return NULL;
}
}
if (!rootfsdir)
rootfsdir = s1;
else
free(s1);
*rootfslen = strlen(rootfsdir);
return rootfsdir;
}
static int mount_entry_create_overlay_dirs(const struct mntent *mntent,
const struct lxc_rootfs *rootfs,
const char *lxc_name,
const char *lxc_path)
{
char lxcpath[MAXPATHLEN];
char *rootfsdir = NULL;
char *upperdir = NULL;
char *workdir = NULL;
char **opts = NULL;
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;
if (!rootfs->path || !lxc_name || !lxc_path)
goto err;
opts = lxc_string_split(mntent->mnt_opts, ',');
if (opts)
arrlen = lxc_array_len((void **)opts);
else
goto err;
for (i = 0; i < arrlen; i++) {
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="))))
workdir = opts[i] + len;
}
ret = snprintf(lxcpath, MAXPATHLEN, "%s/%s", lxc_path, lxc_name);
if (ret < 0 || ret >= MAXPATHLEN)
goto err;
rootfsdir = ovl_get_rootfs_dir(rootfs->path, &rootfslen);
if (!rootfsdir)
goto err;
dirlen = strlen(lxcpath);
/* We neither allow users to create upperdirs and workdirs outside the
* containerdir nor inside the rootfs. The latter might be debatable. */
if (upperdir)
if ((strncmp(upperdir, lxcpath, dirlen) == 0) && (strncmp(upperdir, rootfsdir, rootfslen) != 0))
if (mkdir_p(upperdir, 0755) < 0) {
WARN("Failed to create upperdir");
}
if (workdir)
if ((strncmp(workdir, lxcpath, dirlen) == 0) && (strncmp(workdir, rootfsdir, rootfslen) != 0))
if (mkdir_p(workdir, 0755) < 0) {
WARN("Failed to create workdir");
}
fret = 0;
err:
free(rootfsdir);
lxc_free_array((void **)opts, free);
return fret;
}
static int mount_entry_create_aufs_dirs(const struct mntent *mntent, static int mount_entry_create_aufs_dirs(const struct mntent *mntent,
const struct lxc_rootfs *rootfs, const struct lxc_rootfs *rootfs,
const char *lxc_name, const char *lxc_name,
...@@ -1958,7 +1858,7 @@ static int mount_entry_create_aufs_dirs(const struct mntent *mntent, ...@@ -1958,7 +1858,7 @@ static int mount_entry_create_aufs_dirs(const struct mntent *mntent,
if (ret < 0 || ret >= MAXPATHLEN) if (ret < 0 || ret >= MAXPATHLEN)
goto err; goto err;
rootfsdir = ovl_get_rootfs_dir(rootfs->path, &rootfslen); rootfsdir = ovl_get_rootfs(rootfs->path, &rootfslen);
if (!rootfsdir) if (!rootfsdir)
goto err; goto err;
...@@ -1987,7 +1887,7 @@ static int mount_entry_create_dir_file(const struct mntent *mntent, ...@@ -1987,7 +1887,7 @@ static int mount_entry_create_dir_file(const struct mntent *mntent,
FILE *pathfile = NULL; FILE *pathfile = NULL;
if (strncmp(mntent->mnt_type, "overlay", 7) == 0) { if (strncmp(mntent->mnt_type, "overlay", 7) == 0) {
if (mount_entry_create_overlay_dirs(mntent, rootfs, lxc_name, lxc_path) < 0) if (ovl_mkdir(mntent, rootfs, lxc_name, lxc_path) < 0)
return -1; return -1;
} else if (strncmp(mntent->mnt_type, "aufs", 4) == 0) { } else if (strncmp(mntent->mnt_type, "aufs", 4) == 0) {
if (mount_entry_create_aufs_dirs(mntent, rootfs, lxc_name, lxc_path) < 0) if (mount_entry_create_aufs_dirs(mntent, rootfs, lxc_name, lxc_path) < 0)
...@@ -2623,7 +2523,7 @@ void restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf) ...@@ -2623,7 +2523,7 @@ void restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf)
{ {
int i, ret, oldfd; int i, ret, oldfd;
char path[MAXPATHLEN]; char path[MAXPATHLEN];
char ifname[IFNAMSIZ]; char ifname[IFNAMSIZ];
if (netnsfd < 0) if (netnsfd < 0)
return; return;
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#include "config.h" #include "config.h"
#include "bdev.h" #include "bdev/bdev.h"
#include "cgroup.h" #include "cgroup.h"
#include "conf.h" #include "conf.h"
#include "commands.h" #include "commands.h"
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
#include "conf.h" #include "conf.h"
#include "state.h" #include "state.h"
#include "utils.h" #include "utils.h"
#include "bdev.h" #include "bdev/bdev.h"
#ifndef HAVE_GETSUBOPT #ifndef HAVE_GETSUBOPT
#include <../include/getsubopt.h> #include <../include/getsubopt.h>
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include "lxc.h" #include "lxc.h"
#include "log.h" #include "log.h"
#include "bdev.h" #include "bdev/bdev.h"
#include "arguments.h" #include "arguments.h"
#include "utils.h" #include "utils.h"
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include "lxc.h" #include "lxc.h"
#include "log.h" #include "log.h"
#include "bdev.h" #include "bdev/bdev.h"
#include "arguments.h" #include "arguments.h"
#include "utils.h" #include "utils.h"
......
...@@ -19,48 +19,46 @@ ...@@ -19,48 +19,46 @@
*/ */
#define _GNU_SOURCE #define _GNU_SOURCE
#include <sys/mman.h>
#include <assert.h> #include <assert.h>
#include <stdarg.h> #include <dirent.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <sched.h> #include <grp.h>
#include <dirent.h>
#include <sched.h>
#include <arpa/inet.h>
#include <libgen.h> #include <libgen.h>
#include <pthread.h>
#include <sched.h>
#include <stdarg.h>
#include <stdint.h> #include <stdint.h>
#include <grp.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <lxc/lxccontainer.h> #include "attach.h"
#include <lxc/version.h> #include "bdev/bdev.h"
#include <lxc/network.h> #include "bdev/overlay.h"
#include "cgroup.h"
#include "config.h"
#include "lxc.h"
#include "state.h"
#include "conf.h" #include "conf.h"
#include "config.h"
#include "commands.h"
#include "confile.h" #include "confile.h"
#include "console.h" #include "console.h"
#include "cgroup.h"
#include "commands.h"
#include "criu.h" #include "criu.h"
#include "log.h" #include "log.h"
#include "bdev.h" #include "lxc.h"
#include "utils.h" #include "lxccontainer.h"
#include "attach.h" #include "lxclock.h"
#include "monitor.h" #include "monitor.h"
#include "namespace.h" #include "namespace.h"
#include "network.h" #include "network.h"
#include "lxclock.h"
#include "sync.h" #include "sync.h"
#include "state.h"
#include "utils.h"
#include "version.h"
#if HAVE_IFADDRS_H #if HAVE_IFADDRS_H
#include <ifaddrs.h> #include <ifaddrs.h>
...@@ -1095,9 +1093,9 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_ ...@@ -1095,9 +1093,9 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
* the template * the template
*/ */
if (strncmp(src, "overlayfs:", 10) == 0) if (strncmp(src, "overlayfs:", 10) == 0)
src = overlay_getlower(src+10); src = ovl_getlower(src+10);
if (strncmp(src, "aufs:", 5) == 0) if (strncmp(src, "aufs:", 5) == 0)
src = overlay_getlower(src+5); src = ovl_getlower(src+5);
bdev = bdev_init(c->lxc_conf, src, c->lxc_conf->rootfs.mount, NULL); bdev = bdev_init(c->lxc_conf, src, c->lxc_conf->rootfs.mount, NULL);
if (!bdev) { if (!bdev) {
...@@ -2997,102 +2995,6 @@ static int create_file_dirname(char *path, struct lxc_conf *conf) ...@@ -2997,102 +2995,6 @@ static int create_file_dirname(char *path, struct lxc_conf *conf)
return ret; return ret;
} }
/* 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 . */
static int update_ovl_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;
int i;
int fret = -1;
int ret = 0;
struct lxc_list *iterator;
const char *ovl_dirs[] = {"br", "upperdir", "workdir"};
cleanpath = strdup(newpath);
if (!cleanpath)
goto err;
remove_trailing_slashes(cleanpath);
/* We have to update lxc_conf->unexpanded_config separately from
* lxc_conf->mount_list. */
for (i = 0; i < sizeof(ovl_dirs) / sizeof(ovl_dirs[0]); i++) {
if (!clone_update_unexp_ovl_paths(lxc_conf, lxc_path, newpath,
lxc_name, newname,
ovl_dirs[i]))
goto err;
}
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);
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;
mnt_entry = iterator->elem;
if (strstr(mnt_entry, "overlay"))
tmp = "upperdir";
else if (strstr(mnt_entry, "aufs"))
tmp = "br";
if (!tmp)
continue;
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);
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);
}
if (strstr(mnt_entry, old_work)) {
if (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);
}
if (new_mnt_entry) {
free(iterator->elem);
iterator->elem = strdup(new_mnt_entry);
} else if (tmp_mnt_entry) {
free(iterator->elem);
iterator->elem = strdup(tmp_mnt_entry);
}
free(new_mnt_entry);
free(tmp_mnt_entry);
}
fret = 0;
err:
free(cleanpath);
return fret;
}
static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char *newname, static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char *newname,
const char *lxcpath, int flags, const char *lxcpath, int flags,
const char *bdevtype, const char *bdevdata, uint64_t newsize, const char *bdevtype, const char *bdevdata, uint64_t newsize,
...@@ -3223,7 +3125,7 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char ...@@ -3223,7 +3125,7 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
} }
// update absolute paths for overlay mount directories // update absolute paths for overlay mount directories
if (update_ovl_paths(c2->lxc_conf, c->config_path, c->name, lxcpath, newname) < 0) if (ovl_update_abs_paths(c2->lxc_conf, c->config_path, c->name, lxcpath, newname) < 0)
goto out; goto out;
// We've now successfully created c2's storage, so clear it out if we // We've now successfully created c2's storage, so clear it out if we
......
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
#include "namespace.h" #include "namespace.h"
#include "lxcseccomp.h" #include "lxcseccomp.h"
#include "caps.h" #include "caps.h"
#include "bdev.h" #include "bdev/bdev.h"
#include "lsm/lsm.h" #include "lsm/lsm.h"
#include "lxclock.h" #include "lxclock.h"
......
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