The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxc/pull/1665
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) ===
From d97d4f177282a1d96dfab45ab64333d12d4d0a54 Mon Sep 17 00:00:00 2001 From: Christian Brauner <christian.brau...@ubuntu.com> Date: Sat, 1 Jul 2017 17:02:13 +0200 Subject: [PATCH 1/9] storage: deprecate lxc.rootfs.backend Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com> --- src/lxc/bdev/bdev.c | 41 +++++++++++++++++++++-------------------- src/lxc/bdev/lxcaufs.c | 5 +++-- src/lxc/bdev/lxcbtrfs.c | 5 ++++- src/lxc/bdev/lxcdir.c | 5 +++-- src/lxc/bdev/lxcloop.c | 2 +- src/lxc/bdev/lxclvm.c | 4 ++-- src/lxc/bdev/lxcnbd.c | 3 ++- src/lxc/bdev/lxcoverlay.c | 8 ++++++-- src/lxc/bdev/lxcrbd.c | 6 +++++- src/lxc/bdev/lxczfs.c | 3 +++ src/lxc/confile.c | 22 +++++++--------------- src/lxc/lxccontainer.c | 30 ++++++++++-------------------- 12 files changed, 67 insertions(+), 67 deletions(-) diff --git a/src/lxc/bdev/bdev.c b/src/lxc/bdev/bdev.c index 44c4e0423..55abefa38 100644 --- a/src/lxc/bdev/bdev.c +++ b/src/lxc/bdev/bdev.c @@ -187,11 +187,11 @@ struct bdev_type { }; static const struct bdev_type bdevs[] = { + { .name = "dir", .ops = &dir_ops, }, { .name = "zfs", .ops = &zfs_ops, }, { .name = "lvm", .ops = &lvm_ops, }, { .name = "rbd", .ops = &rbd_ops, }, { .name = "btrfs", .ops = &btrfs_ops, }, - { .name = "dir", .ops = &dir_ops, }, { .name = "aufs", .ops = &aufs_ops, }, { .name = "overlayfs", .ops = &ovl_ops, }, { .name = "loop", .ops = &loop_ops, }, @@ -890,40 +890,41 @@ static struct bdev *bdev_get(const char *type) static const struct bdev_type *get_bdev_by_name(const char *name) { - size_t i; + size_t i, cmplen; - for (i = 0; i < numbdevs; i++) { - if (strcmp(bdevs[i].name, name) == 0) - return &bdevs[i]; - } + cmplen = strcspn(name, ":"); + if (cmplen == 0) + return NULL; - ERROR("Backing store %s unknown but not caught earlier\n", name); - return NULL; + for (i = 0; i < numbdevs; i++) + if (strncmp(bdevs[i].name, name, cmplen) == 0) + break; + + if (i == numbdevs) + return NULL; + + DEBUG("Detected rootfs type \"%s\"", bdevs[i].name); + return &bdevs[i]; } static const struct bdev_type *bdev_query(struct lxc_conf *conf, const char *src) { size_t i; + const struct bdev_type *bdev; - if (conf->rootfs.bdev_type) { - DEBUG("config file specified rootfs type \"%s\"", - conf->rootfs.bdev_type); - return get_bdev_by_name(conf->rootfs.bdev_type); - } + bdev = get_bdev_by_name(src); + if (bdev) + return bdev; - for (i = 0; i < numbdevs; i++) { - int r; - r = bdevs[i].ops->detect(src); - if (r) + for (i = 0; i < numbdevs; i++) + if (bdevs[i].ops->detect(src)) break; - } if (i == numbdevs) return NULL; - DEBUG("detected rootfs type \"%s\"", bdevs[i].name); - + DEBUG("Detected rootfs type \"%s\"", bdevs[i].name); return &bdevs[i]; } diff --git a/src/lxc/bdev/lxcaufs.c b/src/lxc/bdev/lxcaufs.c index fd5e97503..481b62ffe 100644 --- a/src/lxc/bdev/lxcaufs.c +++ b/src/lxc/bdev/lxcaufs.c @@ -229,8 +229,9 @@ int aufs_destroy(struct bdev *orig) int aufs_detect(const char *path) { - if (strncmp(path, "aufs:", 5) == 0) - return 1; // take their word for it + if (!strncmp(path, "aufs:", 5)) + return 1; + return 0; } diff --git a/src/lxc/bdev/lxcbtrfs.c b/src/lxc/bdev/lxcbtrfs.c index 9eaec4a2a..bc0e80502 100644 --- a/src/lxc/bdev/lxcbtrfs.c +++ b/src/lxc/bdev/lxcbtrfs.c @@ -174,10 +174,13 @@ int btrfs_detect(const char *path) struct stat st; int ret; + if (!strncmp(path, "btrfs:", 6)) + return 1; + if (!is_btrfs_fs(path)) return 0; - // and make sure it's a subvolume. + /* make sure it's a subvolume */ ret = stat(path, &st); if (ret < 0) return 0; diff --git a/src/lxc/bdev/lxcdir.c b/src/lxc/bdev/lxcdir.c index fb258405e..be897bb77 100644 --- a/src/lxc/bdev/lxcdir.c +++ b/src/lxc/bdev/lxcdir.c @@ -96,8 +96,9 @@ int dir_destroy(struct bdev *orig) int dir_detect(const char *path) { - if (strncmp(path, "dir:", 4) == 0) - return 1; // take their word for it + if (!strncmp(path, "dir:", 4)) + return 1; + if (is_dir(path)) return 1; return 0; diff --git a/src/lxc/bdev/lxcloop.c b/src/lxc/bdev/lxcloop.c index 65d49525d..9cd63b01a 100644 --- a/src/lxc/bdev/lxcloop.c +++ b/src/lxc/bdev/lxcloop.c @@ -161,7 +161,7 @@ int loop_detect(const char *path) int ret; struct stat s; - if (strncmp(path, "loop:", 5) == 0) + if (!strncmp(path, "loop:", 5)) return 1; ret = stat(path, &s); diff --git a/src/lxc/bdev/lxclvm.c b/src/lxc/bdev/lxclvm.c index 35c5c92f3..407c55ff8 100644 --- a/src/lxc/bdev/lxclvm.c +++ b/src/lxc/bdev/lxclvm.c @@ -134,8 +134,8 @@ int lvm_detect(const char *path) int ret; struct stat statbuf; - if (strncmp(path, "lvm:", 4) == 0) - return 1; // take their word for it + if (!strncmp(path, "lvm:", 4)) + return 1; ret = stat(path, &statbuf); if (ret != 0) diff --git a/src/lxc/bdev/lxcnbd.c b/src/lxc/bdev/lxcnbd.c index 8a320d209..a9bf4f186 100644 --- a/src/lxc/bdev/lxcnbd.c +++ b/src/lxc/bdev/lxcnbd.c @@ -107,8 +107,9 @@ int nbd_destroy(struct bdev *orig) int nbd_detect(const char *path) { - if (strncmp(path, "nbd:", 4) == 0) + if (!strncmp(path, "nbd:", 4)) return 1; + return 0; } diff --git a/src/lxc/bdev/lxcoverlay.c b/src/lxc/bdev/lxcoverlay.c index 65daed8db..377cf9263 100644 --- a/src/lxc/bdev/lxcoverlay.c +++ b/src/lxc/bdev/lxcoverlay.c @@ -298,8 +298,12 @@ int ovl_destroy(struct bdev *orig) int ovl_detect(const char *path) { - if (strncmp(path, "overlayfs:", 10) == 0) - return 1; // take their word for it + if (!strncmp(path, "overlayfs:", 10)) + return 1; + + if (!strncmp(path, "overlay:", 8)) + return 1; + return 0; } diff --git a/src/lxc/bdev/lxcrbd.c b/src/lxc/bdev/lxcrbd.c index b6abb75e4..133b67e52 100644 --- a/src/lxc/bdev/lxcrbd.c +++ b/src/lxc/bdev/lxcrbd.c @@ -154,8 +154,12 @@ int rbd_destroy(struct bdev *orig) int rbd_detect(const char *path) { - if ( memcmp(path, "/dev/rbd/", 9) == 0) + if (!strncmp(path, "rbd:", 4)) return 1; + + if (!strncmp(path, "/dev/rbd/", 9)) + return 1; + return 0; } diff --git a/src/lxc/bdev/lxczfs.c b/src/lxc/bdev/lxczfs.c index 641294560..b8f3c1405 100644 --- a/src/lxc/bdev/lxczfs.c +++ b/src/lxc/bdev/lxczfs.c @@ -70,6 +70,9 @@ int zfs_list_entry(const char *path, char *output, size_t inlen) int zfs_detect(const char *path) { + if (!strncmp(path, "zfs:", 4)) + return 1; + char *output = malloc(LXC_LOG_BUFFER_SIZE); if (!output) { diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 3c0b3b1d0..7fc97f386 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -162,7 +162,12 @@ static struct lxc_config_t config[] = { { "lxc.mount", set_config_fstab, get_config_fstab, clr_config_fstab, }, { "lxc.rootfs.mount", set_config_rootfs_mount, get_config_rootfs_mount, clr_config_rootfs_mount, }, { "lxc.rootfs.options", set_config_rootfs_options, get_config_rootfs_options, clr_config_rootfs_options, }, + + /* REMOVE IN LXC 3.0 + legacy rootfs.backend key + */ { "lxc.rootfs.backend", set_config_rootfs_backend, get_config_rootfs_backend, clr_config_rootfs_backend, }, + { "lxc.rootfs", set_config_rootfs, get_config_rootfs, clr_config_rootfs, }, /* REMOVE IN LXC 3.0 @@ -2051,18 +2056,7 @@ static int set_config_rootfs_options(const char *key, const char *value, static int set_config_rootfs_backend(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { - if (lxc_config_value_empty(value)) { - free(lxc_conf->rootfs.bdev_type); - lxc_conf->rootfs.bdev_type = NULL; - return 0; - } - - if (!is_valid_bdev_type(value)) { - ERROR("Bad rootfs.backend: '%s'", value); - return -1; - } - - return set_config_string_item(&lxc_conf->rootfs.bdev_type, value); + return 0; } static int set_config_uts_name(const char *key, const char *value, @@ -3053,7 +3047,7 @@ static int get_config_rootfs_options(const char *key, char *retv, int inlen, static int get_config_rootfs_backend(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { - return lxc_get_conf_str(retv, inlen, c->rootfs.bdev_type); + return 0; } static int get_config_uts_name(const char *key, char *retv, int inlen, @@ -3473,8 +3467,6 @@ static inline int clr_config_rootfs_options(const char *key, struct lxc_conf *c, static inline int clr_config_rootfs_backend(const char *key, struct lxc_conf *c, void *data) { - free(c->rootfs.bdev_type); - c->rootfs.bdev_type = NULL; return 0; } diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index ae0e708d2..26ae25410 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -1043,7 +1043,7 @@ static bool create_container_dir(struct lxc_container *c) * it returns a mounted bdev on success, NULL on error. */ static struct bdev *do_bdev_create(struct lxc_container *c, const char *type, - struct bdev_specs *specs) + struct bdev_specs *specs) { char *dest; size_t len; @@ -1051,7 +1051,7 @@ static struct bdev *do_bdev_create(struct lxc_container *c, const char *type, int ret; /* rootfs.path or lxcpath/lxcname/rootfs */ - if (c->lxc_conf->rootfs.path && access(c->lxc_conf->rootfs.path, F_OK) == 0) { + if (c->lxc_conf->rootfs.path && !access(c->lxc_conf->rootfs.path, F_OK)) { const char *rpath = c->lxc_conf->rootfs.path; len = strlen(rpath) + 1; dest = alloca(len); @@ -1071,12 +1071,15 @@ static struct bdev *do_bdev_create(struct lxc_container *c, const char *type, return NULL; } - do_lxcapi_set_config_item(c, "lxc.rootfs", bdev->src); - do_lxcapi_set_config_item(c, "lxc.rootfs.backend", bdev->type); - - /* if we are not root, chown the rootfs dir to root in the - * target uidmap */ + if (!c->set_config_item(c, "lxc.rootfs", bdev->src)) { + ERROR("Failed to set config item \"lxc.rootfs\" to \"%s\"", + bdev->src); + return NULL; + } + /* If we are not root, chown the rootfs dir to root in the + * target uidmap. + */ if (geteuid() != 0 || (c->lxc_conf && !lxc_list_empty(&c->lxc_conf->id_map))) { if (chown_mapped_root(bdev->dest, c->lxc_conf) < 0) { ERROR("Error chowning %s to container root", bdev->dest); @@ -2924,20 +2927,12 @@ static int copy_storage(struct lxc_container *c0, struct lxc_container *c, /* Set new rootfs. */ free(c->lxc_conf->rootfs.path); c->lxc_conf->rootfs.path = strdup(bdev->src); - - /* Set new bdev type. */ - free(c->lxc_conf->rootfs.bdev_type); - c->lxc_conf->rootfs.bdev_type = strdup(bdev->type); bdev_put(bdev); if (!c->lxc_conf->rootfs.path) { ERROR("Out of memory while setting storage path."); return -1; } - if (!c->lxc_conf->rootfs.bdev_type) { - ERROR("Out of memory while setting rootfs backend."); - return -1; - } /* Append a new lxc.rootfs entry to the unexpanded config. */ clear_unexp_config_line(c->lxc_conf, "lxc.rootfs", false); @@ -2949,11 +2944,6 @@ static int copy_storage(struct lxc_container *c0, struct lxc_container *c, /* Append a new lxc.rootfs.backend entry to the unexpanded config. */ clear_unexp_config_line(c->lxc_conf, "lxc.rootfs.backend", false); - if (!do_append_unexp_config_line(c->lxc_conf, "lxc.rootfs.backend", - c->lxc_conf->rootfs.bdev_type)) { - ERROR("Error saving new rootfs backend to cloned config."); - return -1; - } if (flags & LXC_CLONE_SNAPSHOT) copy_rdepends(c, c0); From cb5e905919955d367e3788dc905bdf1392c70317 Mon Sep 17 00:00:00 2001 From: Christian Brauner <christian.brau...@ubuntu.com> Date: Sat, 1 Jul 2017 18:15:59 +0200 Subject: [PATCH 2/9] storage: add storage_utils.{c.h} non-functional changes Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com> --- src/lxc/Makefile.am | 2 + src/lxc/bdev/bdev.c | 572 +++++-------------------------------------- src/lxc/bdev/bdev.h | 22 +- src/lxc/bdev/lxcloop.c | 1 + src/lxc/bdev/lxclvm.c | 1 + src/lxc/bdev/lxcnbd.c | 1 + src/lxc/bdev/lxcrbd.c | 1 + src/lxc/bdev/storage_utils.c | 480 ++++++++++++++++++++++++++++++++++++ src/lxc/bdev/storage_utils.h | 54 ++++ src/lxc/start.c | 2 + src/lxc/tools/lxc_create.c | 1 + 11 files changed, 611 insertions(+), 526 deletions(-) create mode 100644 src/lxc/bdev/storage_utils.c create mode 100644 src/lxc/bdev/storage_utils.h diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index ea1982ea7..54fad1226 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -17,6 +17,7 @@ noinst_HEADERS = \ bdev/lxcrbd.h \ bdev/lxcrsync.h \ bdev/lxczfs.h \ + bdev/storage_utils.h \ cgroups/cgroup.h \ caps.h \ conf.h \ @@ -86,6 +87,7 @@ liblxc_la_SOURCES = \ bdev/lxcrbd.c bdev/lxcrbd.h \ bdev/lxcrsync.c bdev/lxcrsync.h \ bdev/lxczfs.c bdev/lxczfs.h \ + bdev/storage_utils.c bdev/storage_utils.h \ cgroups/cgfs.c \ cgroups/cgfsng.c \ cgroups/cgroup.c cgroups/cgroup.h \ diff --git a/src/lxc/bdev/bdev.c b/src/lxc/bdev/bdev.c index 55abefa38..ea1bca17a 100644 --- a/src/lxc/bdev/bdev.c +++ b/src/lxc/bdev/bdev.c @@ -65,6 +65,7 @@ #include "lxczfs.h" #include "namespace.h" #include "parse.h" +#include "storage_utils.h" #include "utils.h" #ifndef BLKGETSIZE64 @@ -200,86 +201,85 @@ static const struct bdev_type bdevs[] = { static const size_t numbdevs = sizeof(bdevs) / sizeof(struct bdev_type); -/* helpers */ -static const struct bdev_type *bdev_query(struct lxc_conf *conf, - const char *src); -static struct bdev *bdev_get(const char *type); -static struct bdev *do_bdev_create(const char *dest, const char *type, - const char *cname, struct bdev_specs *specs); -static int find_fstype_cb(char *buffer, void *data); -static char *linkderef(char *path, char *dest); -static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap, - bool maybesnap); - -/* 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) +static const struct bdev_type *get_bdev_by_name(const char *name) { - 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; - } + size_t i, cmplen; - ret = malloc(nlen); - if (!ret) + cmplen = strcspn(name, ":"); + if (cmplen == 0) return NULL; - p = ret; - if (strncmp(src, oldpath, l1) == 0) { - p += sprintf(p, "%s", lxcpath); - src += l1; - } + for (i = 0; i < numbdevs; i++) + if (strncmp(bdevs[i].name, name, cmplen) == 0) + break; - 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; + if (i == numbdevs) + return NULL; + + DEBUG("Detected rootfs type \"%s\"", bdevs[i].name); + return &bdevs[i]; } -/* - * attach_block_device returns true if all went well, - * meaning either a block device was attached or was not - * needed. It returns false if something went wrong and - * container startup should be stopped. - */ -bool attach_block_device(struct lxc_conf *conf) +const struct bdev_type *bdev_query(struct lxc_conf *conf, const char *src) { - char *path; + size_t i; + const struct bdev_type *bdev; - if (!conf->rootfs.path) - return true; + bdev = get_bdev_by_name(src); + if (bdev) + return bdev; - path = conf->rootfs.path; - if (!requires_nbd(path)) - return true; + for (i = 0; i < numbdevs; i++) + if (bdevs[i].ops->detect(src)) + break; - path = strchr(path, ':'); - if (!path) - return false; + if (i == numbdevs) + return NULL; - path++; - if (!attach_nbd(path, conf)) - return false; + DEBUG("Detected rootfs type \"%s\"", bdevs[i].name); + return &bdevs[i]; +} + +struct bdev *bdev_get(const char *type) +{ + size_t i; + struct bdev *bdev; + + for (i = 0; i < numbdevs; i++) { + if (strcmp(bdevs[i].name, type) == 0) + break; + } + + if (i == numbdevs) + return NULL; + + bdev = malloc(sizeof(struct bdev)); + if (!bdev) + return NULL; + + memset(bdev, 0, sizeof(struct bdev)); + bdev->ops = bdevs[i].ops; + bdev->type = bdevs[i].name; + + return bdev; +} + +static struct bdev *do_bdev_create(const char *dest, const char *type, + const char *cname, struct bdev_specs *specs) +{ + + struct bdev *bdev; + + bdev = bdev_get(type); + if (!bdev) + return NULL; - return true; + if (bdev->ops->create(bdev, dest, cname, specs) < 0) { + bdev_put(bdev); + return NULL; + } + + return bdev; } bool bdev_can_backup(struct lxc_conf *conf) @@ -529,29 +529,6 @@ bool bdev_destroy(struct lxc_conf *conf) return ret; } -int bdev_destroy_wrapper(void *data) -{ - struct lxc_conf *conf = data; - - 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 (!bdev_destroy(conf)) - return -1; - - return 0; -} - struct bdev *bdev_init(struct lxc_conf *conf, const char *src, const char *dst, const char *mntopts) { @@ -607,219 +584,6 @@ void bdev_put(struct bdev *bdev) free(bdev); } -/* - * return block size of dev->src in units of bytes - */ -int blk_getsize(struct bdev *bdev, uint64_t *size) -{ - int fd, ret; - char *path = bdev->src; - - if (strcmp(bdev->type, "loop") == 0) - path = bdev->src + 5; - - fd = open(path, O_RDONLY); - if (fd < 0) - return -1; - - ret = ioctl(fd, BLKGETSIZE64, size); // size of device in bytes - close(fd); - return ret; -} - -void detach_block_device(struct lxc_conf *conf) -{ - if (conf->nbd_idx != -1) - detach_nbd_idx(conf->nbd_idx); -} - -/* - * Given a bdev (presumably blockdev-based), detect the fstype - * by trying mounting (in a private mntns) it. - * @bdev: bdev to investigate - * @type: preallocated char* in which to write the fstype - * @len: length of passed in char* - * Returns length of fstype, of -1 on error - */ -int detect_fs(struct bdev *bdev, char *type, int len) -{ - int p[2], ret; - size_t linelen; - pid_t pid; - FILE *f; - char *sp1, *sp2, *sp3, *line = NULL; - char *srcdev; - - if (!bdev || !bdev->src || !bdev->dest) - return -1; - - srcdev = bdev->src; - if (strcmp(bdev->type, "loop") == 0) - srcdev = bdev->src + 5; - - ret = pipe(p); - if (ret < 0) - return -1; - - if ((pid = fork()) < 0) - return -1; - - if (pid > 0) { - int status; - close(p[1]); - memset(type, 0, len); - ret = read(p[0], type, len - 1); - close(p[0]); - if (ret < 0) { - SYSERROR("error reading from pipe"); - wait(&status); - return -1; - } else if (ret == 0) { - ERROR("child exited early - fstype not found"); - wait(&status); - return -1; - } - wait(&status); - type[len - 1] = '\0'; - INFO("detected fstype %s for %s", type, srcdev); - return ret; - } - - if (unshare(CLONE_NEWNS) < 0) - exit(1); - - if (detect_shared_rootfs()) { - if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL)) { - SYSERROR("Failed to make / rslave"); - ERROR("Continuing..."); - } - } - - ret = mount_unknown_fs(srcdev, bdev->dest, bdev->mntopts); - if (ret < 0) { - ERROR("failed mounting %s onto %s to detect fstype", srcdev, - bdev->dest); - exit(1); - } - - // if symlink, get the real dev name - char devpath[MAXPATHLEN]; - char *l = linkderef(srcdev, devpath); - if (!l) - exit(1); - f = fopen("/proc/self/mounts", "r"); - if (!f) - exit(1); - - while (getline(&line, &linelen, f) != -1) { - sp1 = strchr(line, ' '); - if (!sp1) - exit(1); - *sp1 = '\0'; - if (strcmp(line, l)) - continue; - sp2 = strchr(sp1 + 1, ' '); - if (!sp2) - exit(1); - *sp2 = '\0'; - sp3 = strchr(sp2 + 1, ' '); - if (!sp3) - exit(1); - *sp3 = '\0'; - sp2++; - if (write(p[1], sp2, strlen(sp2)) != strlen(sp2)) - exit(1); - - exit(0); - } - - exit(1); -} - -int do_mkfs_exec_wrapper(void *args) -{ - int ret; - char *mkfs; - char **data = args; - /* strlen("mkfs.") - * + - * strlen(data[0]) - * + - * \0 - */ - size_t len = 5 + strlen(data[0]) + 1; - - mkfs = malloc(len); - if (!mkfs) - return -1; - - ret = snprintf(mkfs, len, "mkfs.%s", data[0]); - if (ret < 0 || (size_t)ret >= len) { - free(mkfs); - return -1; - } - - TRACE("executing \"%s %s\"", mkfs, data[1]); - execlp(mkfs, mkfs, data[1], (char *)NULL); - SYSERROR("failed to run \"%s %s \"", mkfs, data[1]); - return -1; -} - -/* - * This will return 1 for physical disks, qemu-nbd, loop, etc right now only lvm - * is a block device. - */ -int is_blktype(struct bdev *b) -{ - if (strcmp(b->type, "lvm") == 0) - return 1; - - return 0; -} - -int mount_unknown_fs(const char *rootfs, const char *target, - const char *options) -{ - size_t i; - int ret; - struct cbarg { - const char *rootfs; - const char *target; - const char *options; - } cbarg = { - .rootfs = rootfs, - .target = target, - .options = options, - }; - - /* - * find the filesystem type with brute force: - * first we check with /etc/filesystems, in case the modules - * are auto-loaded and fall back to the supported kernel fs - */ - char *fsfile[] = { - "/etc/filesystems", - "/proc/filesystems", - }; - - for (i = 0; i < sizeof(fsfile) / sizeof(fsfile[0]); i++) { - if (access(fsfile[i], F_OK)) - continue; - - ret = lxc_file_for_each_line(fsfile[i], find_fstype_cb, &cbarg); - if (ret < 0) { - ERROR("failed to parse '%s'", fsfile[i]); - return -1; - } - - if (ret) - return 0; - } - - ERROR("failed to determine fs type for '%s'", rootfs); - return -1; -} - bool rootfs_is_blockdev(struct lxc_conf *conf) { const struct bdev_type *q; @@ -845,205 +609,3 @@ bool rootfs_is_blockdev(struct lxc_conf *conf) return false; } - -static struct bdev *do_bdev_create(const char *dest, const char *type, - const char *cname, struct bdev_specs *specs) -{ - - struct bdev *bdev; - - bdev = bdev_get(type); - if (!bdev) - return NULL; - - if (bdev->ops->create(bdev, dest, cname, specs) < 0) { - bdev_put(bdev); - return NULL; - } - - return bdev; -} - -static struct bdev *bdev_get(const char *type) -{ - size_t i; - struct bdev *bdev; - - for (i = 0; i < numbdevs; i++) { - if (strcmp(bdevs[i].name, type) == 0) - break; - } - - if (i == numbdevs) - return NULL; - - bdev = malloc(sizeof(struct bdev)); - if (!bdev) - return NULL; - - memset(bdev, 0, sizeof(struct bdev)); - bdev->ops = bdevs[i].ops; - bdev->type = bdevs[i].name; - - return bdev; -} - -static const struct bdev_type *get_bdev_by_name(const char *name) -{ - size_t i, cmplen; - - cmplen = strcspn(name, ":"); - if (cmplen == 0) - return NULL; - - for (i = 0; i < numbdevs; i++) - if (strncmp(bdevs[i].name, name, cmplen) == 0) - break; - - if (i == numbdevs) - return NULL; - - DEBUG("Detected rootfs type \"%s\"", bdevs[i].name); - return &bdevs[i]; -} - -static const struct bdev_type *bdev_query(struct lxc_conf *conf, - const char *src) -{ - size_t i; - const struct bdev_type *bdev; - - bdev = get_bdev_by_name(src); - if (bdev) - return bdev; - - for (i = 0; i < numbdevs; i++) - if (bdevs[i].ops->detect(src)) - break; - - if (i == numbdevs) - return NULL; - - DEBUG("Detected rootfs type \"%s\"", bdevs[i].name); - return &bdevs[i]; -} - -/* - * These are copied from conf.c. However as conf.c will be moved to using - * the callback system, they can be pulled from there eventually, so we - * don't need to pollute utils.c with these low level functions - */ -static int find_fstype_cb(char *buffer, void *data) -{ - struct cbarg { - const char *rootfs; - const char *target; - const char *options; - } *cbarg = data; - - unsigned long mntflags; - char *mntdata; - char *fstype; - - /* we don't try 'nodev' entries */ - if (strstr(buffer, "nodev")) - return 0; - - fstype = buffer; - fstype += lxc_char_left_gc(fstype, strlen(fstype)); - fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0'; - - DEBUG("trying to mount '%s'->'%s' with fstype '%s'", cbarg->rootfs, - cbarg->target, fstype); - - if (parse_mntopts(cbarg->options, &mntflags, &mntdata) < 0) { - free(mntdata); - return 0; - } - - if (mount(cbarg->rootfs, cbarg->target, fstype, mntflags, mntdata)) { - DEBUG("mount failed with error: %s", strerror(errno)); - free(mntdata); - return 0; - } - - free(mntdata); - - INFO("mounted '%s' on '%s', with fstype '%s'", cbarg->rootfs, - cbarg->target, fstype); - - return 1; -} - -static char *linkderef(char *path, char *dest) -{ - struct stat sbuf; - ssize_t ret; - - ret = stat(path, &sbuf); - if (ret < 0) - return NULL; - - if (!S_ISLNK(sbuf.st_mode)) - return path; - - ret = readlink(path, dest, MAXPATHLEN); - if (ret < 0) { - SYSERROR("error reading link %s", path); - return NULL; - } else if (ret >= MAXPATHLEN) { - ERROR("link in %s too long", path); - return NULL; - } - dest[ret] = '\0'; - - return dest; -} - -/* - * is an unprivileged user allowed to make this kind of snapshot - */ -static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap, - bool maybesnap) -{ - if (!t) { - // new type will be same as original - // (unless snap && b->type == dir, in which case it will be - // overlayfs -- which is also allowed) - if (strcmp(b->type, "dir") == 0 || - strcmp(b->type, "aufs") == 0 || - strcmp(b->type, "overlayfs") == 0 || - strcmp(b->type, "btrfs") == 0 || - strcmp(b->type, "loop") == 0) - return true; - - return false; - } - - // unprivileged users can copy and snapshot dir, overlayfs, - // and loop. In particular, not zfs, btrfs, or lvm. - if (strcmp(t, "dir") == 0 || - strcmp(t, "aufs") == 0 || - strcmp(t, "overlayfs") == 0 || - strcmp(t, "btrfs") == 0 || - strcmp(t, "loop") == 0) - return true; - - return false; -} - -bool is_valid_bdev_type(const char *type) -{ - if (strcmp(type, "dir") == 0 || - strcmp(type, "btrfs") == 0 || - strcmp(type, "aufs") == 0 || - strcmp(type, "loop") == 0 || - strcmp(type, "lvm") == 0 || - strcmp(type, "nbd") == 0 || - strcmp(type, "overlayfs") == 0 || - strcmp(type, "rbd") == 0 || - strcmp(type, "zfs") == 0) - return true; - - return false; -} diff --git a/src/lxc/bdev/bdev.h b/src/lxc/bdev/bdev.h index 1caf3ae72..b723b5080 100644 --- a/src/lxc/bdev/bdev.h +++ b/src/lxc/bdev/bdev.h @@ -124,26 +124,6 @@ bool bdev_destroy(struct lxc_conf *conf); /* callback function to be used with userns_exec_1() */ int bdev_destroy_wrapper(void *data); - -/* Some helpers for lvm, rdb, and/or loop: - * Maybe they should move to a separate implementation and header-file - * (bdev_utils.{c,h}) which can be included in bdev.c? - */ -int blk_getsize(struct bdev *bdev, uint64_t *size); -int detect_fs(struct bdev *bdev, char *type, int len); -int do_mkfs_exec_wrapper(void *args); -int is_blktype(struct bdev *b); -int mount_unknown_fs(const char *rootfs, const char *target, - const char *options); -bool rootfs_is_blockdev(struct lxc_conf *conf); - -/* - * these are really for qemu-nbd support, as container shutdown - * must explicitly request device detach. - */ -bool attach_block_device(struct lxc_conf *conf); -void detach_block_device(struct lxc_conf *conf); - -bool is_valid_bdev_type(const char *type); +extern bool rootfs_is_blockdev(struct lxc_conf *conf); #endif // __LXC_BDEV_H diff --git a/src/lxc/bdev/lxcloop.c b/src/lxc/bdev/lxcloop.c index 9cd63b01a..017ead53a 100644 --- a/src/lxc/bdev/lxcloop.c +++ b/src/lxc/bdev/lxcloop.c @@ -34,6 +34,7 @@ #include "bdev.h" #include "log.h" #include "lxcloop.h" +#include "storage_utils.h" #include "utils.h" lxc_log_define(lxcloop, lxc); diff --git a/src/lxc/bdev/lxclvm.c b/src/lxc/bdev/lxclvm.c index 407c55ff8..9c329a2f3 100644 --- a/src/lxc/bdev/lxclvm.c +++ b/src/lxc/bdev/lxclvm.c @@ -36,6 +36,7 @@ #include "config.h" #include "log.h" #include "lxclvm.h" +#include "storage_utils.h" #include "utils.h" /* major()/minor() */ diff --git a/src/lxc/bdev/lxcnbd.c b/src/lxc/bdev/lxcnbd.c index a9bf4f186..4a55e9fff 100644 --- a/src/lxc/bdev/lxcnbd.c +++ b/src/lxc/bdev/lxcnbd.c @@ -34,6 +34,7 @@ #include "bdev.h" #include "log.h" #include "lxcnbd.h" +#include "storage_utils.h" #include "utils.h" lxc_log_define(lxcnbd, lxc); diff --git a/src/lxc/bdev/lxcrbd.c b/src/lxc/bdev/lxcrbd.c index 133b67e52..8e63c3fd0 100644 --- a/src/lxc/bdev/lxcrbd.c +++ b/src/lxc/bdev/lxcrbd.c @@ -31,6 +31,7 @@ #include "bdev.h" #include "log.h" +#include "storage_utils.h" #include "utils.h" lxc_log_define(lxcrbd, lxc); diff --git a/src/lxc/bdev/storage_utils.c b/src/lxc/bdev/storage_utils.c new file mode 100644 index 000000000..6ca6b51ec --- /dev/null +++ b/src/lxc/bdev/storage_utils.c @@ -0,0 +1,480 @@ +/* + * lxc: linux Container library + * + * Copyright © 2017 Canonical Ltd. + * + * Authors: + * Christian Brauner <christian.brau...@ubuntu.com> + * + * This program 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 program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _GNU_SOURCE +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <grp.h> +#include <inttypes.h> +#include <libgen.h> +#include <sched.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/mount.h> +#include <sys/prctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#include "bdev.h" +#include "log.h" +#include "lxcnbd.h" +#include "parse.h" +#include "storage_utils.h" +#include "utils.h" + +#ifndef BLKGETSIZE64 +#define BLKGETSIZE64 _IOR(0x12, 114, size_t) +#endif + +lxc_log_define(storage_utils, lxc); + +/* 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; +} + +/* + * attach_block_device returns true if all went well, + * meaning either a block device was attached or was not + * needed. It returns false if something went wrong and + * container startup should be stopped. + */ +bool attach_block_device(struct lxc_conf *conf) +{ + char *path; + + if (!conf->rootfs.path) + return true; + + path = conf->rootfs.path; + if (!requires_nbd(path)) + return true; + + path = strchr(path, ':'); + if (!path) + return false; + + path++; + if (!attach_nbd(path, conf)) + return false; + + return true; +} + +/* + * return block size of dev->src in units of bytes + */ +int blk_getsize(struct bdev *bdev, uint64_t *size) +{ + int fd, ret; + char *path = bdev->src; + + if (strcmp(bdev->type, "loop") == 0) + path = bdev->src + 5; + + fd = open(path, O_RDONLY); + if (fd < 0) + return -1; + + ret = ioctl(fd, BLKGETSIZE64, size); // size of device in bytes + close(fd); + return ret; +} + +void detach_block_device(struct lxc_conf *conf) +{ + if (conf->nbd_idx != -1) + detach_nbd_idx(conf->nbd_idx); +} + +/* + * Given a bdev (presumably blockdev-based), detect the fstype + * by trying mounting (in a private mntns) it. + * @bdev: bdev to investigate + * @type: preallocated char* in which to write the fstype + * @len: length of passed in char* + * Returns length of fstype, of -1 on error + */ +int detect_fs(struct bdev *bdev, char *type, int len) +{ + int p[2], ret; + size_t linelen; + pid_t pid; + FILE *f; + char *sp1, *sp2, *sp3, *line = NULL; + char *srcdev; + + if (!bdev || !bdev->src || !bdev->dest) + return -1; + + srcdev = bdev->src; + if (strcmp(bdev->type, "loop") == 0) + srcdev = bdev->src + 5; + + ret = pipe(p); + if (ret < 0) + return -1; + + if ((pid = fork()) < 0) + return -1; + + if (pid > 0) { + int status; + close(p[1]); + memset(type, 0, len); + ret = read(p[0], type, len - 1); + close(p[0]); + if (ret < 0) { + SYSERROR("error reading from pipe"); + wait(&status); + return -1; + } else if (ret == 0) { + ERROR("child exited early - fstype not found"); + wait(&status); + return -1; + } + wait(&status); + type[len - 1] = '\0'; + INFO("detected fstype %s for %s", type, srcdev); + return ret; + } + + if (unshare(CLONE_NEWNS) < 0) + exit(1); + + if (detect_shared_rootfs()) { + if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL)) { + SYSERROR("Failed to make / rslave"); + ERROR("Continuing..."); + } + } + + ret = mount_unknown_fs(srcdev, bdev->dest, bdev->mntopts); + if (ret < 0) { + ERROR("failed mounting %s onto %s to detect fstype", srcdev, + bdev->dest); + exit(1); + } + + // if symlink, get the real dev name + char devpath[MAXPATHLEN]; + char *l = linkderef(srcdev, devpath); + if (!l) + exit(1); + f = fopen("/proc/self/mounts", "r"); + if (!f) + exit(1); + + while (getline(&line, &linelen, f) != -1) { + sp1 = strchr(line, ' '); + if (!sp1) + exit(1); + *sp1 = '\0'; + if (strcmp(line, l)) + continue; + sp2 = strchr(sp1 + 1, ' '); + if (!sp2) + exit(1); + *sp2 = '\0'; + sp3 = strchr(sp2 + 1, ' '); + if (!sp3) + exit(1); + *sp3 = '\0'; + sp2++; + if (write(p[1], sp2, strlen(sp2)) != strlen(sp2)) + exit(1); + + exit(0); + } + + exit(1); +} + +int do_mkfs_exec_wrapper(void *args) +{ + int ret; + char *mkfs; + char **data = args; + /* strlen("mkfs.") + * + + * strlen(data[0]) + * + + * \0 + */ + size_t len = 5 + strlen(data[0]) + 1; + + mkfs = malloc(len); + if (!mkfs) + return -1; + + ret = snprintf(mkfs, len, "mkfs.%s", data[0]); + if (ret < 0 || (size_t)ret >= len) { + free(mkfs); + return -1; + } + + TRACE("executing \"%s %s\"", mkfs, data[1]); + execlp(mkfs, mkfs, data[1], (char *)NULL); + SYSERROR("failed to run \"%s %s \"", mkfs, data[1]); + return -1; +} + +/* + * This will return 1 for physical disks, qemu-nbd, loop, etc right now only lvm + * is a block device. + */ +int is_blktype(struct bdev *b) +{ + if (strcmp(b->type, "lvm") == 0) + return 1; + + return 0; +} + +int mount_unknown_fs(const char *rootfs, const char *target, + const char *options) +{ + size_t i; + int ret; + struct cbarg { + const char *rootfs; + const char *target; + const char *options; + } cbarg = { + .rootfs = rootfs, + .target = target, + .options = options, + }; + + /* + * find the filesystem type with brute force: + * first we check with /etc/filesystems, in case the modules + * are auto-loaded and fall back to the supported kernel fs + */ + char *fsfile[] = { + "/etc/filesystems", + "/proc/filesystems", + }; + + for (i = 0; i < sizeof(fsfile) / sizeof(fsfile[0]); i++) { + if (access(fsfile[i], F_OK)) + continue; + + ret = lxc_file_for_each_line(fsfile[i], find_fstype_cb, &cbarg); + if (ret < 0) { + ERROR("failed to parse '%s'", fsfile[i]); + return -1; + } + + if (ret) + return 0; + } + + ERROR("failed to determine fs type for '%s'", rootfs); + return -1; +} + +/* + * These are copied from conf.c. However as conf.c will be moved to using + * the callback system, they can be pulled from there eventually, so we + * don't need to pollute utils.c with these low level functions + */ +int find_fstype_cb(char *buffer, void *data) +{ + struct cbarg { + const char *rootfs; + const char *target; + const char *options; + } *cbarg = data; + + unsigned long mntflags; + char *mntdata; + char *fstype; + + /* we don't try 'nodev' entries */ + if (strstr(buffer, "nodev")) + return 0; + + fstype = buffer; + fstype += lxc_char_left_gc(fstype, strlen(fstype)); + fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0'; + + DEBUG("trying to mount '%s'->'%s' with fstype '%s'", cbarg->rootfs, + cbarg->target, fstype); + + if (parse_mntopts(cbarg->options, &mntflags, &mntdata) < 0) { + free(mntdata); + return 0; + } + + if (mount(cbarg->rootfs, cbarg->target, fstype, mntflags, mntdata)) { + DEBUG("mount failed with error: %s", strerror(errno)); + free(mntdata); + return 0; + } + + free(mntdata); + + INFO("mounted '%s' on '%s', with fstype '%s'", cbarg->rootfs, + cbarg->target, fstype); + + return 1; +} + +char *linkderef(char *path, char *dest) +{ + struct stat sbuf; + ssize_t ret; + + ret = stat(path, &sbuf); + if (ret < 0) + return NULL; + + if (!S_ISLNK(sbuf.st_mode)) + return path; + + ret = readlink(path, dest, MAXPATHLEN); + if (ret < 0) { + SYSERROR("error reading link %s", path); + return NULL; + } else if (ret >= MAXPATHLEN) { + ERROR("link in %s too long", path); + return NULL; + } + dest[ret] = '\0'; + + return dest; +} + +/* + * is an unprivileged user allowed to make this kind of snapshot + */ +bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap, + bool maybesnap) +{ + if (!t) { + // new type will be same as original + // (unless snap && b->type == dir, in which case it will be + // overlayfs -- which is also allowed) + if (strcmp(b->type, "dir") == 0 || + strcmp(b->type, "aufs") == 0 || + strcmp(b->type, "overlayfs") == 0 || + strcmp(b->type, "btrfs") == 0 || + strcmp(b->type, "loop") == 0) + return true; + + return false; + } + + // unprivileged users can copy and snapshot dir, overlayfs, + // and loop. In particular, not zfs, btrfs, or lvm. + if (strcmp(t, "dir") == 0 || + strcmp(t, "aufs") == 0 || + strcmp(t, "overlayfs") == 0 || + strcmp(t, "btrfs") == 0 || + strcmp(t, "loop") == 0) + return true; + + return false; +} + +bool is_valid_bdev_type(const char *type) +{ + if (strcmp(type, "dir") == 0 || + strcmp(type, "btrfs") == 0 || + strcmp(type, "aufs") == 0 || + strcmp(type, "loop") == 0 || + strcmp(type, "lvm") == 0 || + strcmp(type, "nbd") == 0 || + strcmp(type, "overlayfs") == 0 || + strcmp(type, "rbd") == 0 || + strcmp(type, "zfs") == 0) + return true; + + return false; +} + +int bdev_destroy_wrapper(void *data) +{ + struct lxc_conf *conf = data; + + 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 (!bdev_destroy(conf)) + return -1; + + return 0; +} diff --git a/src/lxc/bdev/storage_utils.h b/src/lxc/bdev/storage_utils.h new file mode 100644 index 000000000..cfd6aa47c --- /dev/null +++ b/src/lxc/bdev/storage_utils.h @@ -0,0 +1,54 @@ +/* + * lxc: linux Container library + * + * Copyright © 2017 Canonical Ltd. + * + * Authors: + * Christian Brauner <christian.brau...@ubuntu.com> + * + * This program 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 program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __LXC_STORAGE_UTILS_H +#define __LXC_STORAGE_UTILS_H + +#include "config.h" +#include <stdio.h> +#include <stdbool.h> +#include <stdint.h> + +#include "conf.h" + +struct bdev; +struct lxc_conf; + +extern char *dir_new_path(char *src, const char *oldname, const char *name, + const char *oldpath, const char *lxcpath); +extern bool attach_block_device(struct lxc_conf *conf); +extern void detach_block_device(struct lxc_conf *conf); +extern int blk_getsize(struct bdev *bdev, uint64_t *size); +extern int detect_fs(struct bdev *bdev, char *type, int len); +extern int do_mkfs_exec_wrapper(void *args); +extern int is_blktype(struct bdev *b); +extern int mount_unknown_fs(const char *rootfs, const char *target, + const char *options); +extern int find_fstype_cb(char *buffer, void *data); +extern char *linkderef(char *path, char *dest); +extern bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap, + bool maybesnap); +extern bool is_valid_bdev_type(const char *type); +extern int bdev_destroy_wrapper(void *data); + +#endif // __LXC_STORAGE_UTILS_H diff --git a/src/lxc/start.c b/src/lxc/start.c index e1acc7c89..2d121bfd5 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -71,6 +71,7 @@ #include "console.h" #include "error.h" #include "log.h" +#include "lxccontainer.h" #include "lxclock.h" #include "lxcseccomp.h" #include "lxcutmp.h" @@ -78,6 +79,7 @@ #include "monitor.h" #include "namespace.h" #include "start.h" +#include "storage_utils.h" #include "sync.h" #include "utils.h" #include "lsm/lsm.h" diff --git a/src/lxc/tools/lxc_create.c b/src/lxc/tools/lxc_create.c index dda51a44d..ad449dcad 100644 --- a/src/lxc/tools/lxc_create.c +++ b/src/lxc/tools/lxc_create.c @@ -30,6 +30,7 @@ #include "bdev.h" #include "log.h" #include "lxc.h" +#include "storage_utils.h" #include "utils.h" lxc_log_define(lxc_create_ui, lxc); From 1af01db5ba879e89f92d9386925cd14824fd8b34 Mon Sep 17 00:00:00 2001 From: Christian Brauner <christian.brau...@ubuntu.com> Date: Sat, 1 Jul 2017 22:36:05 +0200 Subject: [PATCH 3/9] storage: add lxc_storage_get_path() Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com> --- src/lxc/bdev/bdev.c | 11 +++++++++++ src/lxc/bdev/bdev.h | 1 + 2 files changed, 12 insertions(+) diff --git a/src/lxc/bdev/bdev.c b/src/lxc/bdev/bdev.c index ea1bca17a..48f2c2759 100644 --- a/src/lxc/bdev/bdev.c +++ b/src/lxc/bdev/bdev.c @@ -609,3 +609,14 @@ bool rootfs_is_blockdev(struct lxc_conf *conf) return false; } + +char *lxc_storage_get_path(char *src, const char *prefix) +{ + size_t prefix_len; + + prefix_len = strlen(prefix); + if (!strncmp(src, prefix, prefix_len) && (*(src + prefix_len) == ':')) + return (src + prefix_len + 1); + + return src; +} diff --git a/src/lxc/bdev/bdev.h b/src/lxc/bdev/bdev.h index b723b5080..22133173a 100644 --- a/src/lxc/bdev/bdev.h +++ b/src/lxc/bdev/bdev.h @@ -125,5 +125,6 @@ bool bdev_destroy(struct lxc_conf *conf); /* callback function to be used with userns_exec_1() */ int bdev_destroy_wrapper(void *data); extern bool rootfs_is_blockdev(struct lxc_conf *conf); +extern char *lxc_storage_get_path(char *src, const char *prefix); #endif // __LXC_BDEV_H From fd2b982aa3f614fede347653dcad0d59ad519ba1 Mon Sep 17 00:00:00 2001 From: Christian Brauner <christian.brau...@ubuntu.com> Date: Sat, 1 Jul 2017 22:36:27 +0200 Subject: [PATCH 4/9] storage: prefix all dir paths Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com> --- src/lxc/bdev/bdev.c | 7 ++++- src/lxc/bdev/lxcdir.c | 68 ++++++++++++++++++++++++++++++++++++------------- src/lxc/bdev/lxcrsync.c | 1 - src/lxc/lxccontainer.c | 6 +++-- 4 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/lxc/bdev/bdev.c b/src/lxc/bdev/bdev.c index 48f2c2759..1bc8afcd0 100644 --- a/src/lxc/bdev/bdev.c +++ b/src/lxc/bdev/bdev.c @@ -306,6 +306,7 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname, struct bdev *orig, *new; pid_t pid; int ret; + char *src_no_prefix; bool snap = flags & LXC_CLONE_SNAPSHOT; bool maybe_snap = flags & LXC_CLONE_MAYBE_SNAPSHOT; bool keepbdevtype = flags & LXC_CLONE_KEEPBDEVTYPE; @@ -402,7 +403,9 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname, goto err; } - if (am_unpriv() && chown_mapped_root(new->src, c0->lxc_conf) < 0) + src_no_prefix = lxc_storage_get_path(new->src, new->type); + + if (am_unpriv() && chown_mapped_root(src_no_prefix, c0->lxc_conf) < 0) WARN("Failed to update ownership of %s", new->dest); if (snap) @@ -456,6 +459,8 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname, "rsync_rootfs_wrapper"); else ret = rsync_rootfs(&data); + if (ret < 0) + ERROR("Failed to rsync"); exit(ret == 0 ? 0 : 1); diff --git a/src/lxc/bdev/lxcdir.c b/src/lxc/bdev/lxcdir.c index be897bb77..576736ea9 100644 --- a/src/lxc/bdev/lxcdir.c +++ b/src/lxc/bdev/lxcdir.c @@ -39,7 +39,8 @@ int dir_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 len, ret; + int ret; + size_t len; if (snap) { ERROR("directories cannot be snapshotted. Try aufs or overlayfs."); @@ -49,38 +50,58 @@ int dir_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, if (!orig->dest || !orig->src) return -1; - len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3; + len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 4 + 3; new->src = malloc(len); if (!new->src) return -1; - ret = snprintf(new->src, len, "%s/%s/rootfs", lxcpath, cname); - if (ret < 0 || ret >= len) + + ret = snprintf(new->src, len, "dir:%s/%s/rootfs", lxcpath, cname); + if (ret < 0 || (size_t)ret >= len) return -1; - if ((new->dest = strdup(new->src)) == NULL) + + new->dest = strdup(new->src + 4); + if (!new->dest) return -1; return 0; } int dir_create(struct bdev *bdev, const char *dest, const char *n, - struct bdev_specs *specs) + struct bdev_specs *specs) { + int ret; + const char *src; + size_t len; + + /* strlen("dir:") */ + len = 4; if (specs && specs->dir) - bdev->src = strdup(specs->dir); + src = specs->dir; else - bdev->src = strdup(dest); + src = dest; + + len += strlen(src); + bdev->src = malloc(len); + if (!bdev->src) + return -1; + + ret = snprintf(bdev->src, len, "dir:%s", src); + if (ret < 0 || (size_t)ret >= len) + return -1; + bdev->dest = strdup(dest); - if (!bdev->src || !bdev->dest) { - ERROR("Out of memory"); + if (!bdev->dest) return -1; - } - if (mkdir_p(bdev->src, 0755) < 0) { - ERROR("Error creating %s", bdev->src); + ret = mkdir_p(src, 0755); + if (ret < 0) { + ERROR("Failed to create %s", src); return -1; } - if (mkdir_p(bdev->dest, 0755) < 0) { - ERROR("Error creating %s", bdev->dest); + + ret = mkdir_p(bdev->dest, 0755); + if (ret < 0) { + ERROR("Failed to create %s", bdev->dest); return -1; } @@ -89,8 +110,13 @@ int dir_create(struct bdev *bdev, const char *dest, const char *n, int dir_destroy(struct bdev *orig) { - if (lxc_rmdir_onedev(orig->src, NULL) < 0) + char *src; + + src = lxc_storage_get_path(orig->src, orig->src); + + if (lxc_rmdir_onedev(src, NULL) < 0) return -1; + return 0; } @@ -101,17 +127,19 @@ int dir_detect(const char *path) if (is_dir(path)) return 1; + return 0; } int dir_mount(struct bdev *bdev) { unsigned long mntflags; - char *mntdata; + char *src, *mntdata; int ret; if (strcmp(bdev->type, "dir")) return -22; + if (!bdev->src || !bdev->dest) return -22; @@ -120,7 +148,9 @@ int dir_mount(struct bdev *bdev) return -22; } - ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata); + src = lxc_storage_get_path(bdev->src, bdev->type); + + ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata); free(mntdata); return ret; } @@ -129,7 +159,9 @@ int dir_umount(struct bdev *bdev) { if (strcmp(bdev->type, "dir")) return -22; + if (!bdev->src || !bdev->dest) return -22; + return umount(bdev->dest); } diff --git a/src/lxc/bdev/lxcrsync.c b/src/lxc/bdev/lxcrsync.c index 8af39898d..41eb881c4 100644 --- a/src/lxc/bdev/lxcrsync.c +++ b/src/lxc/bdev/lxcrsync.c @@ -139,4 +139,3 @@ int rsync_rootfs_wrapper(void *data) struct rsync_data *arg = data; return rsync_rootfs(arg); } - diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 26ae25410..56a34941d 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -1154,8 +1154,10 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_ exit(1); } } else { // TODO come up with a better way here! + char *src; free(bdev->dest); - bdev->dest = strdup(bdev->src); + src = lxc_storage_get_path(bdev->src, bdev->type); + bdev->dest = strdup(src); } /* @@ -1320,7 +1322,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_ } /* execute */ execvp(tpath, newargv); - SYSERROR("failed to execute template %s", tpath); + SYSERROR("Failed to execute template %s", tpath); exit(1); } From 1df4d53369ed33e3550513bf1970296a5fa0eb23 Mon Sep 17 00:00:00 2001 From: Christian Brauner <christian.brau...@ubuntu.com> Date: Sat, 1 Jul 2017 23:02:45 +0200 Subject: [PATCH 5/9] storage: prefix all btrfs paths Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com> --- src/lxc/bdev/lxcbtrfs.c | 59 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/src/lxc/bdev/lxcbtrfs.c b/src/lxc/bdev/lxcbtrfs.c index bc0e80502..1defa76ee 100644 --- a/src/lxc/bdev/lxcbtrfs.c +++ b/src/lxc/bdev/lxcbtrfs.c @@ -194,11 +194,12 @@ int btrfs_detect(const char *path) int btrfs_mount(struct bdev *bdev) { unsigned long mntflags; - char *mntdata; + char *mntdata, *src; int ret; if (strcmp(bdev->type, "btrfs")) return -22; + if (!bdev->src || !bdev->dest) return -22; @@ -207,7 +208,9 @@ int btrfs_mount(struct bdev *bdev) return -22; } - ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata); + src = lxc_storage_get_path(bdev->src, "btrfs"); + + ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata); free(mntdata); return ret; } @@ -216,8 +219,10 @@ int btrfs_umount(struct bdev *bdev) { if (strcmp(bdev->type, "btrfs")) return -22; + if (!bdev->src || !bdev->dest) return -22; + return umount(bdev->dest); } @@ -346,7 +351,9 @@ int btrfs_snapshot(const char *orig, const char *new) static int btrfs_snapshot_wrapper(void *data) { + char *src; struct rsync_data_char *arg = data; + if (setgid(0) < 0) { ERROR("Failed to setgid to 0"); return -1; @@ -357,7 +364,10 @@ static int btrfs_snapshot_wrapper(void *data) ERROR("Failed to setuid to 0"); return -1; } - return btrfs_snapshot(arg->src, arg->dest); + + src = lxc_storage_get_path(arg->src, "btrfs"); + + return btrfs_snapshot(src, arg->dest); } int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, @@ -365,6 +375,8 @@ int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, const char *lxcpath, int snap, uint64_t newsize, struct lxc_conf *conf) { + char *src; + if (!orig->dest || !orig->src) return -1; @@ -375,21 +387,26 @@ int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, orig->type); return -1; } - len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3; + + len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 6 + 3; new->src = malloc(len); if (!new->src) return -1; - ret = snprintf(new->src, len, "%s/%s/rootfs", lxcpath, cname); + + ret = snprintf(new->src, len, "btrfs:%s/%s/rootfs", lxcpath, cname); if (ret < 0 || ret >= len) return -1; } else { - // in case rootfs is in custom path, reuse it - if ((new->src = dir_new_path(orig->src, oldname, cname, oldpath, lxcpath)) == NULL) + /* In case rootfs is in custom path, reuse it. */ + new->src = dir_new_path(orig->src, oldname, cname, oldpath, lxcpath); + if (!new->src) return -1; } - if ((new->dest = strdup(new->src)) == NULL) + src = lxc_storage_get_path(new->src, "btrfs"); + new->dest = strdup(src); + if (!new->dest) return -1; if (orig->mntopts && (new->mntopts = strdup(orig->mntopts)) == NULL) @@ -734,21 +751,39 @@ bool btrfs_try_remove_subvol(const char *path) { if (!btrfs_detect(path)) return false; + return btrfs_recursive_destroy(path) == 0; } int btrfs_destroy(struct bdev *orig) { - return btrfs_recursive_destroy(orig->src); + char *src; + + src = lxc_storage_get_path(orig->src, "btrfs"); + + return btrfs_recursive_destroy(src); } int btrfs_create(struct bdev *bdev, const char *dest, const char *n, struct bdev_specs *specs) { - bdev->src = strdup(dest); + int ret; + size_t len; + + len = strlen(dest) + 1; + /* strlen("btrfs:") */ + len += 6; + bdev->src = malloc(len); + if (!bdev->src) + return -1; + + ret = snprintf(bdev->src, len, "btrfs:%s", dest); + if (ret < 0 || (size_t)ret >= len) + return -1; + bdev->dest = strdup(dest); - if (!bdev->src || !bdev->dest) + if (!bdev->dest) return -1; + return btrfs_subvolume_create(bdev->dest); } - From 2e04e378fbc5b83c0c4529863eb65030009776c3 Mon Sep 17 00:00:00 2001 From: Christian Brauner <christian.brau...@ubuntu.com> Date: Sat, 1 Jul 2017 23:31:18 +0200 Subject: [PATCH 6/9] storage: prefix all lvm paths Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com> --- src/lxc/bdev/lxclvm.c | 52 ++++++++++++++++++++++++++++++++------------ src/lxc/bdev/storage_utils.c | 15 +++++-------- 2 files changed, 43 insertions(+), 24 deletions(-) diff --git a/src/lxc/bdev/lxclvm.c b/src/lxc/bdev/lxclvm.c index 9c329a2f3..fdbd98707 100644 --- a/src/lxc/bdev/lxclvm.c +++ b/src/lxc/bdev/lxclvm.c @@ -162,21 +162,30 @@ int lvm_detect(const char *path) int lvm_mount(struct bdev *bdev) { + char *src; + if (strcmp(bdev->type, "lvm")) return -22; + if (!bdev->src || !bdev->dest) return -22; - /* if we might pass in data sometime, then we'll have to enrich - * mount_unknown_fs */ - return mount_unknown_fs(bdev->src, bdev->dest, bdev->mntopts); + + src = lxc_storage_get_path(bdev->src, bdev->type); + + /* If we might pass in data sometime, then we'll have to enrich + * mount_unknown_fs(). + */ + return mount_unknown_fs(src, bdev->dest, bdev->mntopts); } int lvm_umount(struct bdev *bdev) { if (strcmp(bdev->type, "lvm")) return -22; + if (!bdev->src || !bdev->dest) return -22; + return umount(bdev->dest); } @@ -298,10 +307,12 @@ int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, return -1; } vg = lxc_global_config_value("lxc.bdev.lvm.vg"); - len = strlen("/dev/") + strlen(vg) + strlen(cname) + 2; - if ((new->src = malloc(len)) == NULL) + len = strlen("/dev/") + strlen(vg) + strlen(cname) + 4 + 2; + new->src = malloc(len); + if (new->src) return -1; - ret = snprintf(new->src, len, "/dev/%s/%s", vg, cname); + + ret = snprintf(new->src, len, "lvm:/dev/%s/%s", vg, cname); if (ret < 0 || ret >= len) return -1; } else { @@ -342,18 +353,26 @@ int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, } if (snap) { - if (lvm_snapshot(orig->src, new->src, size) < 0) { + char *newsrc, *origsrc; + + origsrc = lxc_storage_get_path(orig->src, "lvm"); + newsrc = lxc_storage_get_path(new->src, "lvm"); + + if (lvm_snapshot(origsrc, newsrc, size) < 0) { ERROR("could not create %s snapshot of %s", new->src, orig->src); return -1; } } else { - if (do_lvm_create(new->src, size, lxc_global_config_value("lxc.bdev.lvm.thin_pool")) < 0) { + char *src; + + src = lxc_storage_get_path(new->src, "lvm"); + if (do_lvm_create(src, size, lxc_global_config_value("lxc.bdev.lvm.thin_pool")) < 0) { ERROR("Error creating new lvm blockdev"); return -1; } cmd_args[0] = fstype; - cmd_args[1] = new->src; + cmd_args[1] = src; // create an fs in the loopback file ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper, (void *)cmd_args); @@ -366,15 +385,20 @@ int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, int lvm_destroy(struct bdev *orig) { + char *src; + pid_t pid; if ((pid = fork()) < 0) return -1; + if (!pid) { (void)setenv("LVM_SUPPRESS_FD_WARNINGS", "1", 1); - execlp("lvremove", "lvremove", "-f", orig->src, (char *)NULL); + src = lxc_storage_get_path(orig->src, "lvm"); + execlp("lvremove", "lvremove", "-f", src, (char *)NULL); exit(EXIT_FAILURE); } + return wait_for_pid(pid); } @@ -402,12 +426,12 @@ int lvm_create(struct bdev *bdev, const char *dest, const char *n, if (specs->lvm.lv) lv = specs->lvm.lv; - len = strlen(vg) + strlen(lv) + 7; + len = strlen(vg) + strlen(lv) + 4 + 7; bdev->src = malloc(len); if (!bdev->src) return -1; - ret = snprintf(bdev->src, len, "/dev/%s/%s", vg, lv); + ret = snprintf(bdev->src, len, "lvm:/dev/%s/%s", vg, lv); if (ret < 0 || ret >= len) return -1; @@ -416,7 +440,7 @@ int lvm_create(struct bdev *bdev, const char *dest, const char *n, if (!sz) sz = DEFAULT_FS_SIZE; - if (do_lvm_create(bdev->src, sz, thinpool) < 0) { + if (do_lvm_create(bdev->src + 4, sz, thinpool) < 0) { ERROR("Error creating new lvm blockdev %s size %"PRIu64" bytes", bdev->src, sz); return -1; } @@ -426,7 +450,7 @@ int lvm_create(struct bdev *bdev, const char *dest, const char *n, fstype = DEFAULT_FSTYPE; cmd_args[0] = fstype; - cmd_args[1] = bdev->src; + cmd_args[1] = bdev->src + 4; ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper, (void *)cmd_args); if (ret < 0) diff --git a/src/lxc/bdev/storage_utils.c b/src/lxc/bdev/storage_utils.c index 6ca6b51ec..0cf9710fb 100644 --- a/src/lxc/bdev/storage_utils.c +++ b/src/lxc/bdev/storage_utils.c @@ -129,12 +129,10 @@ bool attach_block_device(struct lxc_conf *conf) int blk_getsize(struct bdev *bdev, uint64_t *size) { int fd, ret; - char *path = bdev->src; + char *src; - if (strcmp(bdev->type, "loop") == 0) - path = bdev->src + 5; - - fd = open(path, O_RDONLY); + src = lxc_storage_get_path(bdev->src, bdev->type); + fd = open(src, O_RDONLY); if (fd < 0) return -1; @@ -163,15 +161,12 @@ int detect_fs(struct bdev *bdev, char *type, int len) size_t linelen; pid_t pid; FILE *f; - char *sp1, *sp2, *sp3, *line = NULL; - char *srcdev; + char *sp1, *sp2, *sp3, *srcdev, *line = NULL; if (!bdev || !bdev->src || !bdev->dest) return -1; - srcdev = bdev->src; - if (strcmp(bdev->type, "loop") == 0) - srcdev = bdev->src + 5; + srcdev = lxc_storage_get_path(bdev->src, bdev->type); ret = pipe(p); if (ret < 0) From 1cc9eee2692e22a3db09babe9a796e0f1cbf3880 Mon Sep 17 00:00:00 2001 From: Christian Brauner <christian.brau...@ubuntu.com> Date: Sat, 1 Jul 2017 23:33:18 +0200 Subject: [PATCH 7/9] storage: prefix all nbd paths Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com> --- src/lxc/bdev/lxcnbd.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/lxc/bdev/lxcnbd.c b/src/lxc/bdev/lxcnbd.c index 4a55e9fff..e6ce59038 100644 --- a/src/lxc/bdev/lxcnbd.c +++ b/src/lxc/bdev/lxcnbd.c @@ -117,17 +117,21 @@ int nbd_detect(const char *path) int nbd_mount(struct bdev *bdev) { int ret = -1, partition; + char *src; char path[50]; if (strcmp(bdev->type, "nbd")) return -22; + if (!bdev->src || !bdev->dest) return -22; /* nbd_idx should have been copied by bdev_init from the lxc_conf */ if (bdev->nbd_idx < 0) return -22; - partition = nbd_get_partition(bdev->src); + + src = lxc_storage_get_path(bdev->src, bdev->type); + partition = nbd_get_partition(src); if (partition) ret = snprintf(path, 50, "/dev/nbd%dp%d", bdev->nbd_idx, partition); @@ -152,14 +156,13 @@ int nbd_mount(struct bdev *bdev) int nbd_umount(struct bdev *bdev) { - int ret; - if (strcmp(bdev->type, "nbd")) return -22; + if (!bdev->src || !bdev->dest) return -22; - ret = umount(bdev->dest); - return ret; + + return umount(bdev->dest); } bool requires_nbd(const char *path) From 4cacc022d9342269e90ec8d8cac14ad63d3e59cc Mon Sep 17 00:00:00 2001 From: Christian Brauner <christian.brau...@ubuntu.com> Date: Sat, 1 Jul 2017 23:35:58 +0200 Subject: [PATCH 8/9] storage: prefix all rbd paths Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com> --- src/lxc/bdev/lxcrbd.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/lxc/bdev/lxcrbd.c b/src/lxc/bdev/lxcrbd.c index 8e63c3fd0..85001400b 100644 --- a/src/lxc/bdev/lxcrbd.c +++ b/src/lxc/bdev/lxcrbd.c @@ -66,12 +66,12 @@ int rbd_create(struct bdev *bdev, const char *dest, const char *n, rbdname = specs->rbd.rbdname; /* source device /dev/rbd/lxc/ctn */ - len = strlen(rbdpool) + strlen(rbdname) + 11; + len = strlen(rbdpool) + strlen(rbdname) + 4 + 11; bdev->src = malloc(len); if (!bdev->src) return -1; - ret = snprintf(bdev->src, len, "/dev/rbd/%s/%s", rbdpool, rbdname); + ret = snprintf(bdev->src, len, "rbd:/dev/rbd/%s/%s", rbdpool, rbdname); if (ret < 0 || ret >= len) return -1; @@ -108,7 +108,7 @@ int rbd_create(struct bdev *bdev, const char *dest, const char *n, fstype = DEFAULT_FSTYPE; cmd_args[0] = fstype; - cmd_args[1] = bdev->src; + cmd_args[1] = bdev->src + 4; ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper, (void *)cmd_args); if (ret < 0) @@ -127,14 +127,16 @@ int rbd_create(struct bdev *bdev, const char *dest, const char *n, int rbd_destroy(struct bdev *orig) { + char *src; pid_t pid; char *rbdfullname; - if ( file_exists(orig->src) ) { + src = lxc_storage_get_path(orig->src, orig->type); + if (file_exists(src)) { if ((pid = fork()) < 0) return -1; if (!pid) { - execlp("rbd", "rbd", "unmap" , orig->src, (char *)NULL); + execlp("rbd", "rbd", "unmap" , src, (char *)NULL); exit(1); } if (wait_for_pid(pid) < 0) @@ -144,8 +146,8 @@ int rbd_destroy(struct bdev *orig) if ((pid = fork()) < 0) return -1; if (!pid) { - rbdfullname = alloca(strlen(orig->src) - 8); - strcpy( rbdfullname, &orig->src[9] ); + rbdfullname = alloca(strlen(src) - 8); + strcpy( rbdfullname, &src[9] ); execlp("rbd", "rbd", "rm" , rbdfullname, (char *)NULL); exit(1); } @@ -166,12 +168,15 @@ int rbd_detect(const char *path) int rbd_mount(struct bdev *bdev) { + char *src; if (strcmp(bdev->type, "rbd")) return -22; + if (!bdev->src || !bdev->dest) return -22; - if ( !file_exists(bdev->src) ) { + src = lxc_storage_get_path(bdev->src, bdev->type); + if (!file_exists(src)) { // if blkdev does not exist it should be mapped, because it is not persistent on reboot ERROR("Block device %s is not mapped.", bdev->src); return -1; @@ -184,7 +189,9 @@ int rbd_umount(struct bdev *bdev) { if (strcmp(bdev->type, "rbd")) return -22; + if (!bdev->src || !bdev->dest) return -22; + return umount(bdev->dest); } From 214e6e2aeaa47dadd894144099545e01e064628e Mon Sep 17 00:00:00 2001 From: Christian Brauner <christian.brau...@ubuntu.com> Date: Sat, 1 Jul 2017 23:41:49 +0200 Subject: [PATCH 9/9] storage: prefix all zfs paths Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com> --- src/lxc/bdev/lxczfs.c | 77 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/src/lxc/bdev/lxczfs.c b/src/lxc/bdev/lxczfs.c index b8f3c1405..8fe74137d 100644 --- a/src/lxc/bdev/lxczfs.c +++ b/src/lxc/bdev/lxczfs.c @@ -88,20 +88,23 @@ int zfs_detect(const char *path) int zfs_mount(struct bdev *bdev) { + int ret; + char *mntdata, *src; + unsigned long mntflags; + if (strcmp(bdev->type, "zfs")) return -22; if (!bdev->src || !bdev->dest) return -22; - char *mntdata; - unsigned long mntflags; if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) { free(mntdata); return -22; } - int ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata); + src = lxc_storage_get_path(bdev->src, bdev->type); + ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata); free(mntdata); return ret; @@ -208,6 +211,7 @@ int zfs_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 *origsrc, *newsrc; int len, ret; if (!orig->src || !orig->dest) @@ -218,19 +222,22 @@ int zfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, return -1; } - len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3; + len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 4 + 3; new->src = malloc(len); if (!new->src) return -1; - ret = snprintf(new->src, len, "%s/%s/rootfs", lxcpath, cname); + ret = snprintf(new->src, len, "zfs:%s/%s/rootfs", lxcpath, cname); if (ret < 0 || ret >= len) return -1; - if ((new->dest = strdup(new->src)) == NULL) + newsrc = lxc_storage_get_path(new->src, new->type); + new->dest = strdup(newsrc); + if (!new->dest) return -1; - return zfs_clone(orig->src, new->src, oldname, cname, lxcpath, snap); + origsrc = lxc_storage_get_path(orig->src, orig->type); + return zfs_clone(origsrc, newsrc, oldname, cname, lxcpath, snap); } /* @@ -242,14 +249,15 @@ int zfs_destroy(struct bdev *orig) { pid_t pid; char output[MAXPATHLEN]; - char *p; + char *p, *src; if ((pid = fork()) < 0) return -1; if (pid) return wait_for_pid(pid); - if (!zfs_list_entry(orig->src, output, MAXPATHLEN)) { + src = lxc_storage_get_path(orig->src, orig->type); + if (!zfs_list_entry(src, output, MAXPATHLEN)) { ERROR("Error: zfs entry for %s not found", orig->src); return -1; } @@ -263,41 +271,64 @@ int zfs_destroy(struct bdev *orig) exit(EXIT_FAILURE); } +struct zfs_exec_args { + char *dataset; + char *options; +}; + +int zfs_create_exec_wrapper(void *args) +{ + struct zfs_exec_args *zfs_args = args; + + execlp("zfs", "zfs", "create", zfs_args->options, zfs_args->dataset, + (char *)NULL); + return -1; +} + int zfs_create(struct bdev *bdev, const char *dest, const char *n, struct bdev_specs *specs) { const char *zfsroot; - char option[MAXPATHLEN]; + char cmd_output[MAXPATHLEN], dev[MAXPATHLEN], option[MAXPATHLEN]; int ret; - pid_t pid; + size_t len; + struct zfs_exec_args cmd_args; if (!specs || !specs->zfs.zfsroot) zfsroot = lxc_global_config_value("lxc.bdev.zfs.root"); else zfsroot = specs->zfs.zfsroot; - if (!(bdev->dest = strdup(dest))) { + bdev->dest = strdup(dest); + if (!bdev->dest) { ERROR("No mount target specified or out of memory"); return -1; } - if (!(bdev->src = strdup(bdev->dest))) { - ERROR("out of memory"); + + len = strlen(bdev->dest) + 1; + /* strlen("zfs:") */ + len += 4; + bdev->src = malloc(len); + if (!bdev->src) + return -1; + + ret = snprintf(bdev->src, len, "zfs:%s", bdev->dest); + if (ret < 0 || (size_t)ret >= len) return -1; - } ret = snprintf(option, MAXPATHLEN, "-omountpoint=%s", bdev->dest); if (ret < 0 || ret >= MAXPATHLEN) return -1; - if ((pid = fork()) < 0) - return -1; - if (pid) - return wait_for_pid(pid); - char dev[MAXPATHLEN]; ret = snprintf(dev, MAXPATHLEN, "%s/%s", zfsroot, n); if (ret < 0 || ret >= MAXPATHLEN) - exit(EXIT_FAILURE); + return -1; - execlp("zfs", "zfs", "create", option, dev, (char *)NULL); - exit(EXIT_FAILURE); + cmd_args.options = option; + cmd_args.dataset = dev; + ret = run_command(cmd_output, sizeof(cmd_output), + zfs_create_exec_wrapper, (void *)&cmd_args); + if (ret < 0) + ERROR("Failed to create zfs dataset \"%s\": %s", dev, cmd_output); + return ret; }
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel