[lxc-devel] [lxc/master] [WIP] deprecate lxc.rootfs.backend

brauner on Github lxc-bot at linuxcontainers.org
Sat Jul 1 22:44:57 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170701/3ba2e224/attachment.bin>
-------------- next part --------------
From d97d4f177282a1d96dfab45ab64333d12d4d0a54 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at 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.brauner at 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.brauner at 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.brauner at 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.brauner at 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.brauner at 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.brauner at 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.brauner at 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.brauner at 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.brauner at 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.brauner at 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.brauner at 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.brauner at 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.brauner at 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.brauner at 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.brauner at 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.brauner at 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.brauner at 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.brauner at 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.brauner at 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;
 }


More information about the lxc-devel mailing list