<p dir="ltr">Will tgis work for unprivileged containers as well?</p>
<div class="gmail_quote">On May 14, 2014 9:36 AM, "Dwight Engen" <<a href="mailto:dwight.engen@oracle.com">dwight.engen@oracle.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
On Mon, 12 May 2014 18:02:28 +0000<br>
Serge Hallyn <<a href="mailto:serge.hallyn@ubuntu.com">serge.hallyn@ubuntu.com</a>> wrote:<br>
<br>
> qcow2 backing stores can be attached to a nbd block device using<br>
> qemu-nbd.  This user-space process (pair) stays around for the<br>
> duration of the device attachment.  Obviously we want it to go<br>
> away when the container shuts down, but not before the filesystems<br>
> have been cleanly unmounted.<br>
><br>
> The device attachment is done from the task which will become the<br>
> container monitor before the container setup+init task is spawned.<br>
> That task starts in a new pid namespace to ensure that the qemu-nbd<br>
> process will be killed if need be.  It sets its parent death signal<br>
> to sighup, and, on receiving sighup, attempts to do a clean<br>
> qemu-device detach, then exits.  This should ensure that the<br>
> device is detached if the qemu monitor crashes or exits.<br>
><br>
> It may be worth adding a delay before the qemu-nbd is detached, but<br>
> my brief tests haven't seen any data corruption.<br>
><br>
> Only the parts required for running a qcow2-backed container are<br>
> implemented here.  Create, destroy, and clone are not.  The first<br>
> use of this that I imagine is for people to use downloaded<br>
> qcow2-backed images (like ubuntu cloud images, or anything previously<br>
> used with qemu).  I imagine people will want to create/clone/destroy<br>
> out of band using qemu-img, but if I'm wrong about that we can<br>
> implement the rest later.<br>
><br>
> Because attach_block_device() is done before the bdev is initialized,<br>
> and bdev_init needs to know the nbd index so that it can mount the<br>
> filesystem, we now need to pass the lxc_conf.<br>
><br>
> file_exists() is moved to utils.c so we can use it from bdev.c<br>
><br>
> The nbd attach/detach should lay the groundwork for trivial<br>
> implementation of qed and raw images.<br>
><br>
> changelog (may 12): qcow: fix idx check at detach<br>
<br>
Hey Serge, I had to check the code for how to use this so maybe we<br>
should document somewhere what the rootfs line needs to look like (ie.<br>
lxc.rootfs = qcow2:/path/to/diskimg:1).<br>
<br>
Also, I used this against a .vdi image just fine, so maybe we should be<br>
more generic than just qcow2 and call it qemu? Not sure if qemu-nbd<br>
supports all the same image formats as qemu-img.<br>
<br>
For anyone else trying to use this note that I had to:<br>
'modprobe nbd max_part=16' or else I would only get the full device node<br>
(/dev/nbd0) but not the partition nodes (/dev/nbd0p?) which caused lxc<br>
to hang on startup.<br>
<br>
At any rate, this works great so thanks and:<br>
<br>
Acked-by: Dwight Engen <<a href="mailto:dwight.engen@oracle.com">dwight.engen@oracle.com</a>><br>
<br>
> Signed-off-by: Serge Hallyn <<a href="mailto:serge.hallyn@ubuntu.com">serge.hallyn@ubuntu.com</a>><br>
> ---<br>
>  src/lxc/bdev.c         | 296<br>
> ++++++++++++++++++++++++++++++++++++++++++++++++-<br>
> src/lxc/bdev.h         |  18 ++- src/lxc/conf.c         |   3 +-<br>
>  src/lxc/conf.h         |   1 +<br>
>  src/lxc/lxccontainer.c |  19 +---<br>
>  src/lxc/start.c        |  11 +-<br>
>  src/lxc/utils.c        |   7 ++<br>
>  src/lxc/utils.h        |   1 +<br>
>  8 files changed, 333 insertions(+), 23 deletions(-)<br>
><br>
> diff --git a/src/lxc/bdev.c b/src/lxc/bdev.c<br>
> index 20e9fb3..85b95a7 100644<br>
> --- a/src/lxc/bdev.c<br>
> +++ b/src/lxc/bdev.c<br>
> @@ -41,6 +41,7 @@<br>
>  #include <libgen.h><br>
>  #include <linux/loop.h><br>
>  #include <dirent.h><br>
> +#include <sys/prctl.h><br>
><br>
>  #include "lxc.h"<br>
>  #include "config.h"<br>
> @@ -2410,6 +2411,290 @@ static const struct bdev_ops aufs_ops = {<br>
>       .can_snapshot = true,<br>
>  };<br>
><br>
> +//<br>
> +// qcow2 dev ops<br>
> +//<br>
> +<br>
> +static int qcow2_detect(const char *path)<br>
> +{<br>
> +     if (strncmp(path, "qcow2:", 6) == 0)<br>
> +             return 1;<br>
> +     return 0;<br>
> +}<br>
> +<br>
> +struct nbd_attach_data {<br>
> +     const char *nbd;<br>
> +     const char *path;<br>
> +};<br>
> +<br>
> +static void nbd_detach(const char *path)<br>
> +{<br>
> +     int ret;<br>
> +     pid_t pid = fork();<br>
> +<br>
> +     if (pid < 0) {<br>
> +             SYSERROR("Error forking to detach nbd");<br>
> +             return;<br>
> +     }<br>
> +     if (pid) {<br>
> +             ret = wait_for_pid(pid);<br>
> +             if (ret < 0)<br>
> +                     ERROR("nbd disconnect returned an error");<br>
> +             return;<br>
> +     }<br>
> +     execlp("qemu-nbd", "qemu-nbd", "-d", path, NULL);<br>
> +     SYSERROR("Error executing qemu-nbd");<br>
> +     exit(1);<br>
> +}<br>
> +<br>
> +static int do_attach_nbd(void *d)<br>
> +{<br>
> +     struct nbd_attach_data *data = d;<br>
> +     const char *nbd, *path;<br>
> +     pid_t pid;<br>
> +     sigset_t mask;<br>
> +     int sfd;<br>
> +     ssize_t s;<br>
> +     struct signalfd_siginfo fdsi;<br>
> +<br>
> +     sigemptyset(&mask);<br>
> +     sigaddset(&mask, SIGHUP);<br>
> +     sigaddset(&mask, SIGCHLD);<br>
> +<br>
> +     nbd = data->nbd;<br>
> +     path = data->path;<br>
> +<br>
> +     if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {<br>
> +             SYSERROR("Error blocking signals for nbd watcher");<br>
> +             exit(1);<br>
> +     }<br>
> +<br>
> +     sfd = signalfd(-1, &mask, 0);<br>
> +     if (sfd == -1) {<br>
> +             SYSERROR("Error opening signalfd for nbd task");<br>
> +             exit(1);<br>
> +     }<br>
> +<br>
> +     if (prctl(PR_SET_PDEATHSIG, SIGHUP, 0, 0, 0) < 0)<br>
> +             SYSERROR("Error setting parent death signal for nbd<br>
> watcher"); +<br>
> +     pid = fork();<br>
> +     if (pid) {<br>
> +             for (;;) {<br>
> +                     s = read(sfd, &fdsi, sizeof(struct<br>
> signalfd_siginfo));<br>
> +                     if (s != sizeof(struct signalfd_siginfo))<br>
> +                             SYSERROR("Error reading from<br>
> signalfd"); +<br>
> +                     if (fdsi.ssi_signo == SIGHUP) {<br>
> +                             /* container has exited */<br>
> +                             nbd_detach(nbd);<br>
> +                             exit(0);<br>
> +                     } else if (fdsi.ssi_signo == SIGCHLD) {<br>
> +                             int status;<br>
> +                             while (waitpid(-1, &status, WNOHANG)<br>
> > 0);<br>
> +                     }<br>
> +             }<br>
> +     }<br>
> +<br>
> +     close(sfd);<br>
> +     if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)<br>
> +             WARN("Warning: unblocking signals for nbd watcher");<br>
> +<br>
> +     execlp("qemu-nbd", "qemu-nbd", "-c", nbd, path, NULL);<br>
> +     SYSERROR("Error executing qemu-nbd");<br>
> +     exit(1);<br>
> +}<br>
> +<br>
> +static bool clone_attach_nbd(const char *nbd, const char *path)<br>
> +{<br>
> +     pid_t pid;<br>
> +     struct nbd_attach_data data;<br>
> +<br>
> +     data.nbd = nbd;<br>
> +     data.path = path;<br>
> +<br>
> +     pid = lxc_clone(do_attach_nbd, &data, CLONE_NEWPID);<br>
> +     if (pid < 0)<br>
> +             return false;<br>
> +     return true;<br>
> +}<br>
> +<br>
> +static bool nbd_busy(int idx)<br>
> +{<br>
> +     char path[100];<br>
> +     int ret;<br>
> +<br>
> +     ret = snprintf(path, 100, "/sys/block/nbd%d/pid", idx);<br>
> +     if (ret < 0 || ret >= 100)<br>
> +             return true;<br>
> +     return file_exists(path);<br>
> +}<br>
> +<br>
> +static bool attach_nbd(char *src, struct lxc_conf *conf)<br>
> +{<br>
> +     char *orig = alloca(strlen(src)+1), *p, path[50];<br>
> +     int i = 0;<br>
> +<br>
> +     strcpy(orig, src);<br>
> +     /* if path is followed by a partition, drop that for now */<br>
> +     p = strchr(orig, ':');<br>
> +     if (p)<br>
> +             *p = '\0';<br>
> +     while (1) {<br>
> +             sprintf(path, "/dev/nbd%d", i);<br>
> +             if (!file_exists(path))<br>
> +                     return false;<br>
> +             if (nbd_busy(i)) {<br>
> +                     i++;<br>
> +                     continue;<br>
> +             }<br>
> +             if (!clone_attach_nbd(path, orig))<br>
> +                     return false;<br>
> +             conf->nbd_idx = i;<br>
> +             return true;<br>
> +     }<br>
> +}<br>
> +<br>
> +static bool requires_nbd(const char *path)<br>
> +{<br>
> +     if (strncmp(path, "qcow2:", 6) == 0)<br>
> +             return true;<br>
> +     if (strncmp(path, "raw:", 4) == 0)<br>
> +             return true;<br>
> +     return false;<br>
> +}<br>
> +<br>
> +/*<br>
> + * attach_block_device returns true if all went well,<br>
> + * meaning either a block device was attached or was not<br>
> + * needed.  It returns false if something went wrong and<br>
> + * container startup shoudl be stopped.<br>
> + */<br>
> +bool attach_block_device(struct lxc_conf *conf)<br>
> +{<br>
> +     char *path;<br>
> +<br>
> +     if (!conf->rootfs.path)<br>
> +             return true;<br>
> +     path = conf->rootfs.path;<br>
> +     if (!requires_nbd(path))<br>
> +             return true;<br>
> +     path = strchr(path, ':');<br>
> +     if (!path)<br>
> +             return false;<br>
> +     path++;<br>
> +     if (!attach_nbd(path, conf))<br>
> +             return false;<br>
> +     return true;<br>
> +}<br>
> +<br>
> +void detach_nbd_idx(int idx)<br>
> +{<br>
> +     int ret;<br>
> +     char path[50];<br>
> +<br>
> +     ret = snprintf(path, 50, "/dev/nbd%d", idx);<br>
> +     if (ret < 0 || ret >= 50)<br>
> +             return;<br>
> +<br>
> +     nbd_detach(path);<br>
> +}<br>
> +<br>
> +void detach_block_device(struct lxc_conf *conf)<br>
> +{<br>
> +     if (conf->nbd_idx != -1)<br>
> +             detach_nbd_idx(conf->nbd_idx);<br>
> +}<br>
> +<br>
> +/*<br>
> + * Pick the partition # off the end of a qcow2:file:p<br>
> + * description.  Return 1-9 for the partition id, or 0<br>
> + * for no partition.<br>
> + */<br>
> +static int qcow2_get_partition(const char *src)<br>
> +{<br>
> +     char *p = strchr(src, ':');<br>
> +     if (!p)<br>
> +             return 0;<br>
> +     p = strchr(p+1, ':');<br>
> +     if (!p)<br>
> +             return 0;<br>
> +     p++;<br>
> +     if (*p < '1' && *p > '9')<br>
> +             return 0;<br>
> +     return *p - '0';<br>
> +}<br>
> +<br>
> +static int qcow2_mount(struct bdev *bdev)<br>
> +{<br>
> +     int ret = -1, partition;<br>
> +     char path[50];<br>
> +<br>
> +     if (strcmp(bdev->type, "qcow2"))<br>
> +             return -22;<br>
> +     if (!bdev->src || !bdev->dest)<br>
> +             return -22;<br>
> +<br>
> +     /* nbd_idx should have been copied by bdev_init from the<br>
> lxc_conf */<br>
> +     if (bdev->nbd_idx < 0)<br>
> +             return -22;<br>
> +     partition = qcow2_get_partition(bdev->src);<br>
> +     if (partition)<br>
> +             ret = snprintf(path, 50, "/dev/nbd%dp%d",<br>
> bdev->nbd_idx,<br>
> +                             partition);<br>
> +     else<br>
> +             ret = snprintf(path, 50, "/dev/nbd%d",<br>
> bdev->nbd_idx);<br>
> +     if (ret < 0 || ret >= 50) {<br>
> +             ERROR("Error setting up nbd device path");<br>
> +             return ret;<br>
> +     }<br>
> +     ret = mount_unknown_fs(path, bdev->dest, bdev->mntopts);<br>
> +     if (ret < 0)<br>
> +             ERROR("Error mounting %s", bdev->src);<br>
> +<br>
> +     return ret;<br>
> +}<br>
> +<br>
> +static int qcow2_create(struct bdev *bdev, const char *dest, const<br>
> char *n,<br>
> +                     struct bdev_specs *specs)<br>
> +{<br>
> +     return -ENOSYS;<br>
> +}<br>
> +<br>
> +/* qcow2 should shine here...  */<br>
> +static int qcow2_clonepaths(struct bdev *orig, struct bdev *new,<br>
> const char *oldname,<br>
> +             const char *cname, const char *oldpath, const char<br>
> *lxcpath, int snap,<br>
> +             uint64_t newsize, struct lxc_conf *conf)<br>
> +{<br>
> +     return -ENOSYS;<br>
> +}<br>
> +<br>
> +static int qcow2_destroy(struct bdev *orig)<br>
> +{<br>
> +     return -ENOSYS;<br>
> +}<br>
> +<br>
> +static int qcow2_umount(struct bdev *bdev)<br>
> +{<br>
> +     int ret;<br>
> +<br>
> +     if (strcmp(bdev->type, "qcow2"))<br>
> +             return -22;<br>
> +     if (!bdev->src || !bdev->dest)<br>
> +             return -22;<br>
> +     ret = umount(bdev->dest);<br>
> +     return ret;<br>
> +}<br>
> +<br>
> +static const struct bdev_ops qcow2_ops = {<br>
> +     .detect = &qcow2_detect,<br>
> +     .mount = &qcow2_mount,<br>
> +     .umount = &qcow2_umount,<br>
> +     .clone_paths = &qcow2_clonepaths,<br>
> +     .destroy = &qcow2_destroy,<br>
> +     .create = &qcow2_create,<br>
> +     .can_snapshot = true,<br>
> +};<br>
><br>
>  static const struct bdev_type bdevs[] = {<br>
>       {.name = "zfs", .ops = &zfs_ops,},<br>
> @@ -2419,6 +2704,7 @@ static const struct bdev_type bdevs[] = {<br>
>       {.name = "aufs", .ops = &aufs_ops,},<br>
>       {.name = "overlayfs", .ops = &overlayfs_ops,},<br>
>       {.name = "loop", .ops = &loop_ops,},<br>
> +     {.name = "qcow2", .ops = &qcow2_ops,},<br>
>  };<br>
><br>
>  static const size_t numbdevs = sizeof(bdevs) / sizeof(struct<br>
> bdev_type); @@ -2454,7 +2740,7 @@ struct bdev *bdev_get(const char<br>
> *type) return bdev;<br>
>  }<br>
><br>
> -struct bdev *bdev_init(const char *src, const char *dst, const char<br>
> *mntopts) +struct bdev *bdev_init(struct lxc_conf *conf, const char<br>
> *src, const char *dst, const char *mntopts) {<br>
>       int i;<br>
>       struct bdev *bdev;<br>
> @@ -2480,6 +2766,8 @@ struct bdev *bdev_init(const char *src, const<br>
> char *dst, const char *mntopts) bdev->src = strdup(src);<br>
>       if (dst)<br>
>               bdev->dest = strdup(dst);<br>
> +     if (strcmp(bdev->type, "qcow2") == 0 || strcmp(bdev->type,<br>
> "raw") == 0)<br>
> +             bdev->nbd_idx = conf->nbd_idx;<br>
><br>
>       return bdev;<br>
>  }<br>
> @@ -2538,9 +2826,9 @@ static int rsync_rootfs_wrapper(void *data)<br>
>       return rsync_rootfs(arg);<br>
>  }<br>
><br>
> -bool bdev_is_dir(const char *path)<br>
> +bool bdev_is_dir(struct lxc_conf *conf, const char *path)<br>
>  {<br>
> -     struct bdev *orig = bdev_init(path, NULL, NULL);<br>
> +     struct bdev *orig = bdev_init(conf, path, NULL, NULL);<br>
>       bool ret = false;<br>
>       if (!orig)<br>
>               return ret;<br>
> @@ -2605,7 +2893,7 @@ struct bdev *bdev_copy(struct lxc_container<br>
> *c0, const char *cname, return NULL;<br>
>       }<br>
><br>
> -     orig = bdev_init(src, NULL, NULL);<br>
> +     orig = bdev_init(c0->lxc_conf, src, NULL, NULL);<br>
>       if (!orig) {<br>
>               ERROR("failed to detect blockdev type for %s", src);<br>
>               return NULL;<br>
> diff --git a/src/lxc/bdev.h b/src/lxc/bdev.h<br>
> index cc0bf02..170a530 100644<br>
> --- a/src/lxc/bdev.h<br>
> +++ b/src/lxc/bdev.h<br>
> @@ -24,8 +24,8 @@<br>
>  #ifndef __LXC_BDEV_H<br>
>  #define __LXC_BDEV_H<br>
>  /* blockdev operations for:<br>
> - * aufs, dir, raw, btrfs, overlayfs, aufs, lvm, loop, zfs<br>
> - * someday: qemu-nbd, qcow2, qed<br>
> + * aufs, dir, raw, btrfs, overlayfs, aufs, lvm, loop, zfs, qcow2<br>
> + * someday: qed<br>
>   */<br>
><br>
>  #include "config.h"<br>
> @@ -83,11 +83,13 @@ struct bdev {<br>
>       // turn the following into a union if need be<br>
>       // lofd is the open fd for the mounted loopback file<br>
>       int lofd;<br>
> +     // index for the connected nbd device<br>
> +     int nbd_idx;<br>
>  };<br>
><br>
>  char *overlay_getlower(char *p);<br>
><br>
> -bool bdev_is_dir(const char *path);<br>
> +bool bdev_is_dir(struct lxc_conf *conf, const char *path);<br>
><br>
>  /*<br>
>   * Instantiate a bdev object.  The src is used to determine which<br>
> blockdev @@ -100,7 +102,8 @@ bool bdev_is_dir(const char *path);<br>
>   * use /var/lib/lxc/canonical/rootfs as lower dir,<br>
> and /var/lib/lxc/c1/delta<br>
>   * as the upper, writeable layer.<br>
>   */<br>
> -struct bdev *bdev_init(const char *src, const char *dst, const char<br>
> *data); +struct bdev *bdev_init(struct lxc_conf *conf, const char<br>
> *src, const char *dst,<br>
> +                     const char *data);<br>
><br>
>  struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,<br>
>                       const char *lxcpath, const char *bdevtype,<br>
> @@ -110,6 +113,13 @@ struct bdev *bdev_create(const char *dest, const<br>
> char *type, const char *cname, struct bdev_specs *specs);<br>
>  void bdev_put(struct bdev *bdev);<br>
><br>
> +/*<br>
> + * these are really for qemu-nbd support, as container shutdown<br>
> + * must explicitly request device detach.<br>
> + */<br>
> +bool attach_block_device(struct lxc_conf *conf);<br>
> +void detach_block_device(struct lxc_conf *conf);<br>
> +<br>
>  /* define constants if the kernel/glibc headers don't define them */<br>
>  #ifndef MS_DIRSYNC<br>
>  #define MS_DIRSYNC  128<br>
> diff --git a/src/lxc/conf.c b/src/lxc/conf.c<br>
> index 78d9de2..7427a94 100644<br>
> --- a/src/lxc/conf.c<br>
> +++ b/src/lxc/conf.c<br>
> @@ -1555,7 +1555,7 @@ static int setup_rootfs(struct lxc_conf *conf)<br>
>       }<br>
><br>
>       // First try mounting rootfs using a bdev<br>
> -     struct bdev *bdev = bdev_init(rootfs->path, rootfs->mount,<br>
> rootfs->options);<br>
> +     struct bdev *bdev = bdev_init(conf, rootfs->path,<br>
> rootfs->mount, rootfs->options); if (bdev && bdev->ops->mount(bdev)<br>
> == 0) { bdev_put(bdev);<br>
>               DEBUG("mounted '%s' on '%s'", rootfs->path,<br>
> rootfs->mount); @@ -2675,6 +2675,7 @@ struct lxc_conf<br>
> *lxc_conf_init(void) new->console.slave = -1;<br>
>       new-><a href="http://console.name" target="_blank">console.name</a>[0] = '\0';<br>
>       new->maincmd_fd = -1;<br>
> +     new->nbd_idx = -1;<br>
>       new->rootfs.mount = strdup(default_rootfs_mount);<br>
>       if (!new->rootfs.mount) {<br>
>               ERROR("lxc_conf_init : %m");<br>
> diff --git a/src/lxc/conf.h b/src/lxc/conf.h<br>
> index 865b87a..3a81d0e 100644<br>
> --- a/src/lxc/conf.h<br>
> +++ b/src/lxc/conf.h<br>
> @@ -334,6 +334,7 @@ struct lxc_conf {<br>
>       int start_delay;<br>
>       int start_order;<br>
>       struct lxc_list groups;<br>
> +     int nbd_idx;<br>
>  };<br>
><br>
>  int run_lxc_hooks(const char *name, char *hook, struct lxc_conf<br>
> *conf, diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c<br>
> index 255fde5..fdac433 100644<br>
> --- a/src/lxc/lxccontainer.c<br>
> +++ b/src/lxc/lxccontainer.c<br>
> @@ -82,13 +82,6 @@ return -1;<br>
><br>
>  lxc_log_define(lxc_container, lxc);<br>
><br>
> -static bool file_exists(const char *f)<br>
> -{<br>
> -     struct stat statbuf;<br>
> -<br>
> -     return stat(f, &statbuf) == 0;<br>
> -}<br>
> -<br>
>  static bool config_file_exists(const char *lxcpath, const char<br>
> *cname) {<br>
>       /* $lxcpath + '/' + $cname + '/config' + \0 */<br>
> @@ -900,7 +893,7 @@ static bool create_run_template(struct<br>
> lxc_container *c, char *tpath, bool quiet if (strncmp(src, "aufs:",<br>
> 5) == 0) src = overlay_getlower(src+5);<br>
><br>
> -             bdev = bdev_init(src, c->lxc_conf->rootfs.mount,<br>
> NULL);<br>
> +             bdev = bdev_init(c->lxc_conf, src,<br>
> c->lxc_conf->rootfs.mount, NULL); if (!bdev) {<br>
>                       ERROR("Error opening rootfs");<br>
>                       exit(1);<br>
> @@ -1992,7 +1985,7 @@ static int do_bdev_destroy(struct lxc_conf<br>
> *conf) struct bdev *r;<br>
>       int ret = 0;<br>
><br>
> -     r = bdev_init(conf->rootfs.path, conf->rootfs.mount, NULL);<br>
> +     r = bdev_init(conf, conf->rootfs.path, conf->rootfs.mount,<br>
> NULL); if (!r)<br>
>               return -1;<br>
><br>
> @@ -2522,7 +2515,7 @@ static int clone_update_rootfs(struct<br>
> clone_update_data *data)<br>
>       if (unshare(CLONE_NEWNS) < 0)<br>
>               return -1;<br>
> -     bdev = bdev_init(c->lxc_conf->rootfs.path,<br>
> c->lxc_conf->rootfs.mount, NULL);<br>
> +     bdev = bdev_init(c->lxc_conf, c->lxc_conf->rootfs.path,<br>
> c->lxc_conf->rootfs.mount, NULL); if (!bdev)<br>
>               return -1;<br>
>       if (strcmp(bdev->type, "dir") != 0) {<br>
> @@ -2787,7 +2780,7 @@ static bool lxcapi_rename(struct lxc_container<br>
> *c, const char *newname) if (!c || !c->name || !c->config_path<br>
> || !c->lxc_conf) return false;<br>
><br>
> -     bdev = bdev_init(c->lxc_conf->rootfs.path,<br>
> c->lxc_conf->rootfs.mount, NULL);<br>
> +     bdev = bdev_init(c->lxc_conf, c->lxc_conf->rootfs.path,<br>
> c->lxc_conf->rootfs.mount, NULL); if (!bdev) {<br>
>               ERROR("Failed to find original backing store type");<br>
>               return false;<br>
> @@ -2880,7 +2873,7 @@ static int lxcapi_snapshot(struct lxc_container<br>
> *c, const char *commentfile) */<br>
>       flags = LXC_CLONE_SNAPSHOT | LXC_CLONE_KEEPMACADDR |<br>
> LXC_CLONE_KEEPNAME | LXC_CLONE_KEEPBDEVTYPE |<br>
> LXC_CLONE_MAYBE_SNAPSHOT;<br>
> -     if (bdev_is_dir(c->lxc_conf->rootfs.path)) {<br>
> +     if (bdev_is_dir(c->lxc_conf, c->lxc_conf->rootfs.path)) {<br>
>               ERROR("Snapshot of directory-backed container<br>
> requested."); ERROR("Making a copy-clone.  If you do want snapshots,<br>
> then"); ERROR("please create an aufs or overlayfs clone first,<br>
> snapshot that"); @@ -3082,7 +3075,7 @@ static bool<br>
> lxcapi_snapshot_restore(struct lxc_container *c, const char *snapnam<br>
> if (!c || !c->name || !c->config_path) return false;<br>
><br>
> -     bdev = bdev_init(c->lxc_conf->rootfs.path,<br>
> c->lxc_conf->rootfs.mount, NULL);<br>
> +     bdev = bdev_init(c->lxc_conf, c->lxc_conf->rootfs.path,<br>
> c->lxc_conf->rootfs.mount, NULL); if (!bdev) {<br>
>               ERROR("Failed to find original backing store type");<br>
>               return false;<br>
> diff --git a/src/lxc/start.c b/src/lxc/start.c<br>
> index df1304a..a7fb1d3 100644<br>
> --- a/src/lxc/start.c<br>
> +++ b/src/lxc/start.c<br>
> @@ -69,6 +69,7 @@<br>
>  #include "namespace.h"<br>
>  #include "lxcseccomp.h"<br>
>  #include "caps.h"<br>
> +#include "bdev.h"<br>
>  #include "lsm/lsm.h"<br>
><br>
>  lxc_log_define(lxc_start, lxc);<br>
> @@ -1054,10 +1055,15 @@ int __lxc_start(const char *name, struct<br>
> lxc_conf *conf, handler->conf->need_utmp_watch = 0;<br>
>       }<br>
><br>
> +     if (!attach_block_device(handler->conf)) {<br>
> +             ERROR("Failure attaching block device");<br>
> +             goto out_fini_nonet;<br>
> +     }<br>
> +<br>
>       err = lxc_spawn(handler);<br>
>       if (err) {<br>
>               ERROR("failed to spawn '%s'", name);<br>
> -             goto out_fini_nonet;<br>
> +             goto out_detach_blockdev;<br>
>       }<br>
><br>
>       netnsfd = get_netns_fd(handler->pid);<br>
> @@ -1110,6 +1116,9 @@ int __lxc_start(const char *name, struct<br>
> lxc_conf *conf, out_fini:<br>
>       lxc_delete_network(handler);<br>
><br>
> +out_detach_blockdev:<br>
> +     detach_block_device(handler->conf);<br>
> +<br>
>  out_fini_nonet:<br>
>       lxc_fini(name, handler);<br>
>       return err;<br>
> diff --git a/src/lxc/utils.c b/src/lxc/utils.c<br>
> index efec414..b076ce7 100644<br>
> --- a/src/lxc/utils.c<br>
> +++ b/src/lxc/utils.c<br>
> @@ -1306,3 +1306,10 @@ next_loop:<br>
>       free(path);<br>
>       return NULL;<br>
>  }<br>
> +<br>
> +bool file_exists(const char *f)<br>
> +{<br>
> +     struct stat statbuf;<br>
> +<br>
> +     return stat(f, &statbuf) == 0;<br>
> +}<br>
> diff --git a/src/lxc/utils.h b/src/lxc/utils.h<br>
> index b5e054c..9c618b7 100644<br>
> --- a/src/lxc/utils.h<br>
> +++ b/src/lxc/utils.h<br>
> @@ -280,3 +280,4 @@ uint64_t fnv_64a_buf(void *buf, size_t len,<br>
> uint64_t hval); int detect_shared_rootfs(void);<br>
>  int detect_ramfs_rootfs(void);<br>
>  char *on_path(char *cmd);<br>
> +bool file_exists(const char *f);<br>
<br>
_______________________________________________<br>
lxc-devel mailing list<br>
<a href="mailto:lxc-devel@lists.linuxcontainers.org">lxc-devel@lists.linuxcontainers.org</a><br>
<a href="http://lists.linuxcontainers.org/listinfo/lxc-devel" target="_blank">http://lists.linuxcontainers.org/listinfo/lxc-devel</a><br>
</blockquote></div>