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

Reply via email to