]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
Split bdev into modules: lxczfs
authorChristian Brauner <christian.brauner@mailbox.org>
Tue, 29 Dec 2015 12:35:53 +0000 (13:35 +0100)
committerChristian Brauner <christian.brauner@mailbox.org>
Tue, 12 Jan 2016 07:50:45 +0000 (08:50 +0100)
The functions:

- zfs_clone();
- zfs_clonepaths();
- zfs_create();
- zfs_destroy();
- zfs_detect();
- zfs_list_entry();
- zfs_mount();
- zfs_umount();

move from bdev.c to lxczfs.{c,h}. All functions previously declared as static
become public.

Adapt Makefile.am to include lxczfs.{c,h}.

The structs:

- struct bdev; /* defined in bdev.h */
- struct bdev_specs; /* defined in lxccontainer.h */
- struct lxc_conf; /* defined conf.h */

are forward declared/put as incomplete types into lxczfs.h as the functions
associated with zfs need access to it.

Minor changes:

- Use exit(EXIT_FAILURE) instead of exit(1).
- Use brackets around else {} if the if {} did:
I.e. instead of:

if {
// do one;
// do two;
} else
// do three;

use:

if {
// do one;
// do two;
} else {
// do three;
}
- Instead of declaring char pointers and arrays on the same line, i.e.:

char arr[len], *p;

  do:

char arr[len];
char *p;

  which makes intentions a lot clearer.

- Since we require c99 anyway, use finer-grained scoping by declaring
  variables where they are needed instead of simply at the top.

Signed-off-by: Christian Brauner <christian.brauner@mailbox.org>
src/lxc/Makefile.am
src/lxc/bdev/bdev.c
src/lxc/bdev/lxczfs.c [new file with mode: 0644]
src/lxc/bdev/lxczfs.h [new file with mode: 0644]

index f24e03d4baef75d5597a1c16dd39b9dc3ea258d8..ec605612f9e21bc17f4ba3e20593498231fab509 100644 (file)
@@ -10,6 +10,7 @@ noinst_HEADERS = \
        bdev/lxcbtrfs.h \
        bdev/lxcoverlay.h \
        bdev/lxcrsync.h \
+       bdev/lxczfs.h \
        caps.h \
        cgroup.h \
        conf.h \
@@ -66,6 +67,7 @@ liblxc_so_SOURCES = \
        bdev/lxcbtrfs.c bdev/lxcbtrfs.h \
        bdev/lxcoverlay.c bdev/lxcoverlay.h \
        bdev/lxcrsync.c bdev/lxcrsync.h \
+       bdev/lxczfs.c bdev/lxczfs.h \
        commands.c commands.h \
        start.c start.h \
        execute.c \
index ec0856ec92e3a142904b53a8f0076216f10999c7..8a650d7770c26b7fa4c9ed2bfffa8a9aa84fac12 100644 (file)
@@ -57,6 +57,7 @@
 #include "lxclock.h"
 #include "lxcoverlay.h"
 #include "lxcrsync.h"
+#include "lxczfs.h"
 #include "namespace.h"
 #include "parse.h"
 #include "utils.h"
@@ -491,271 +492,6 @@ static const struct bdev_ops dir_ops = {
        .can_backup = true,
 };
 
-
-//
-// XXXXXXX zfs ops
-// There are two ways we could do this.  We could always specify the
-// 'zfs device' (i.e. tank/lxc lxc/container) as rootfs.  But instead
-// (at least right now) we have lxc-create specify $lxcpath/$lxcname/rootfs
-// as the mountpoint, so that it is always mounted.
-//
-// That means 'mount' is really never needed and could be noop, but for the
-// sake of flexibility let's always bind-mount.
-//
-
-static int zfs_list_entry(const char *path, char *output, size_t inlen)
-{
-       struct lxc_popen_FILE *f;
-       int found=0;
-
-       f = lxc_popen("zfs list 2> /dev/null");
-       if (f == NULL) {
-               SYSERROR("popen failed");
-               return 0;
-       }
-       while (fgets(output, inlen, f->f)) {
-               if (strstr(output, path)) {
-                       found = 1;
-                       break;
-               }
-       }
-       (void) lxc_pclose(f);
-
-       return found;
-}
-
-static int zfs_detect(const char *path)
-{
-       char *output = malloc(LXC_LOG_BUFFER_SIZE);
-       int found;
-
-       if (!output) {
-               ERROR("out of memory");
-               return 0;
-       }
-       found = zfs_list_entry(path, output, LXC_LOG_BUFFER_SIZE);
-       free(output);
-       return found;
-}
-
-static int zfs_mount(struct bdev *bdev)
-{
-       unsigned long mntflags;
-       char *mntdata;
-       int ret;
-
-       if (strcmp(bdev->type, "zfs"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-
-       if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
-               free(mntdata);
-               return -22;
-       }
-
-       ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
-       free(mntdata);
-       return ret;
-}
-
-static int zfs_umount(struct bdev *bdev)
-{
-       if (strcmp(bdev->type, "zfs"))
-               return -22;
-       if (!bdev->src || !bdev->dest)
-               return -22;
-       return umount(bdev->dest);
-}
-
-static int zfs_clone(const char *opath, const char *npath, const char *oname,
-                       const char *nname, const char *lxcpath, int snapshot)
-{
-       // use the 'zfs list | grep opath' entry to get the zfsroot
-       char output[MAXPATHLEN], option[MAXPATHLEN], *p;
-       const char *zfsroot = output;
-       int ret;
-       pid_t pid;
-
-       if (zfs_list_entry(opath, output, MAXPATHLEN)) {
-               // zfsroot is output up to ' '
-               if ((p = strchr(output, ' ')) == NULL)
-                       return -1;
-               *p = '\0';
-               if ((p = strrchr(output, '/')) == NULL)
-                       return -1;
-               *p = '\0';
-       } else
-               zfsroot = lxc_global_config_value("lxc.bdev.zfs.root");
-
-       ret = snprintf(option, MAXPATHLEN, "-omountpoint=%s/%s/rootfs",
-               lxcpath, nname);
-       if (ret < 0  || ret >= MAXPATHLEN)
-               return -1;
-
-       // zfs create -omountpoint=$lxcpath/$lxcname $zfsroot/$nname
-       if (!snapshot) {
-               if ((pid = fork()) < 0)
-                       return -1;
-               if (!pid) {
-                       char dev[MAXPATHLEN];
-
-                       ret = snprintf(dev, MAXPATHLEN, "%s/%s", zfsroot, nname);
-                       if (ret < 0  || ret >= MAXPATHLEN)
-                               exit(1);
-                       execlp("zfs", "zfs", "create", option, dev, NULL);
-                       exit(1);
-               }
-               return wait_for_pid(pid);
-       } else {
-               // if snapshot, do
-               // 'zfs snapshot zfsroot/oname@nname
-               // zfs clone zfsroot/oname@nname zfsroot/nname
-               char path1[MAXPATHLEN], path2[MAXPATHLEN];
-
-               ret = snprintf(path1, MAXPATHLEN, "%s/%s@%s", zfsroot,
-                       oname, nname);
-               if (ret < 0 || ret >= MAXPATHLEN)
-                       return -1;
-               (void) snprintf(path2, MAXPATHLEN, "%s/%s", zfsroot, nname);
-
-               // if the snapshot exists, delete it
-               if ((pid = fork()) < 0)
-                       return -1;
-               if (!pid) {
-                       execlp("zfs", "zfs", "destroy", path1, NULL);
-                       exit(1);
-               }
-               // it probably doesn't exist so destroy probably will fail.
-               (void) wait_for_pid(pid);
-
-               // run first (snapshot) command
-               if ((pid = fork()) < 0)
-                       return -1;
-               if (!pid) {
-                       execlp("zfs", "zfs", "snapshot", path1, NULL);
-                       exit(1);
-               }
-               if (wait_for_pid(pid) < 0)
-                       return -1;
-
-               // run second (clone) command
-               if ((pid = fork()) < 0)
-                       return -1;
-               if (!pid) {
-                       execlp("zfs", "zfs", "clone", option, path1, path2, NULL);
-                       exit(1);
-               }
-               return wait_for_pid(pid);
-       }
-}
-
-static 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)
-{
-       int len, ret;
-
-       if (!orig->src || !orig->dest)
-               return -1;
-
-       if (snap && strcmp(orig->type, "zfs")) {
-               ERROR("zfs snapshot from %s backing store is not supported",
-                       orig->type);
-               return -1;
-       }
-
-       len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 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)
-               return -1;
-       if ((new->dest = strdup(new->src)) == NULL)
-               return -1;
-
-       return zfs_clone(orig->src, new->src, oldname, cname, lxcpath, snap);
-}
-
-/*
- * TODO: detect whether this was a clone, and if so then also delete the
- * snapshot it was based on, so that we don't hold the original
- * container busy.
- */
-static int zfs_destroy(struct bdev *orig)
-{
-       pid_t pid;
-       char output[MAXPATHLEN], *p;
-
-       if ((pid = fork()) < 0)
-               return -1;
-       if (pid)
-               return wait_for_pid(pid);
-
-       if (!zfs_list_entry(orig->src, output, MAXPATHLEN)) {
-               ERROR("Error: zfs entry for %s not found", orig->src);
-               return -1;
-       }
-
-       // zfs mount is output up to ' '
-       if ((p = strchr(output, ' ')) == NULL)
-               return -1;
-       *p = '\0';
-
-       execlp("zfs", "zfs", "destroy", output, NULL);
-       exit(1);
-}
-
-static int zfs_create(struct bdev *bdev, const char *dest, const char *n,
-                       struct bdev_specs *specs)
-{
-       const char *zfsroot;
-       char option[MAXPATHLEN];
-       int ret;
-       pid_t pid;
-
-       if (!specs || !specs->zfs.zfsroot)
-               zfsroot = lxc_global_config_value("lxc.bdev.zfs.root");
-       else
-               zfsroot = specs->zfs.zfsroot;
-
-       if (!(bdev->dest = strdup(dest))) {
-               ERROR("No mount target specified or out of memory");
-               return -1;
-       }
-       if (!(bdev->src = strdup(bdev->dest))) {
-               ERROR("out of memory");
-               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(1);
-       execlp("zfs", "zfs", "create", option, dev, NULL);
-       exit(1);
-}
-
-static const struct bdev_ops zfs_ops = {
-       .detect = &zfs_detect,
-       .mount = &zfs_mount,
-       .umount = &zfs_umount,
-       .clone_paths = &zfs_clonepaths,
-       .destroy = &zfs_destroy,
-       .create = &zfs_create,
-       .can_snapshot = true,
-       .can_backup = true,
-};
-
 //
 // LVM ops
 //
@@ -1628,6 +1364,18 @@ static const struct bdev_ops ovl_ops = {
        .can_backup = true,
 };
 
+/* zfs */
+static const struct bdev_ops zfs_ops = {
+       .detect = &zfs_detect,
+       .mount = &zfs_mount,
+       .umount = &zfs_umount,
+       .clone_paths = &zfs_clonepaths,
+       .destroy = &zfs_destroy,
+       .create = &zfs_create,
+       .can_snapshot = true,
+       .can_backup = true,
+};
+
 //
 // aufs ops
 //
diff --git a/src/lxc/bdev/lxczfs.c b/src/lxc/bdev/lxczfs.c
new file mode 100644 (file)
index 0000000..def5083
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+
+#include "bdev.h"
+#include "config.h"
+#include "log.h"
+#include "lxczfs.h"
+#include "utils.h"
+
+lxc_log_define(lxczfs, lxc);
+
+/*
+ * zfs ops:
+ * There are two ways we could do this. We could always specify the 'zfs device'
+ * (i.e. tank/lxc lxc/container) as rootfs. But instead (at least right now) we
+ * have lxc-create specify $lxcpath/$lxcname/rootfs as the mountpoint, so that
+ * it is always mounted. That means 'mount' is really never needed and could be
+ * noop, but for the sake of flexibility let's always bind-mount.
+ */
+
+int zfs_list_entry(const char *path, char *output, size_t inlen)
+{
+       struct lxc_popen_FILE *f;
+       int found=0;
+
+       f = lxc_popen("zfs list 2> /dev/null");
+       if (f == NULL) {
+               SYSERROR("popen failed");
+               return 0;
+       }
+
+       while (fgets(output, inlen, f->f)) {
+               if (strstr(output, path)) {
+                       found = 1;
+                       break;
+               }
+       }
+       (void) lxc_pclose(f);
+
+       return found;
+}
+
+int zfs_detect(const char *path)
+{
+       char *output = malloc(LXC_LOG_BUFFER_SIZE);
+
+       if (!output) {
+               ERROR("out of memory");
+               return 0;
+       }
+
+       int found = zfs_list_entry(path, output, LXC_LOG_BUFFER_SIZE);
+       free(output);
+
+       return found;
+}
+
+int zfs_mount(struct bdev *bdev)
+{
+       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);
+       free(mntdata);
+
+       return ret;
+}
+
+int zfs_umount(struct bdev *bdev)
+{
+       if (strcmp(bdev->type, "zfs"))
+               return -22;
+
+       if (!bdev->src || !bdev->dest)
+               return -22;
+
+       return umount(bdev->dest);
+}
+
+int zfs_clone(const char *opath, const char *npath, const char *oname,
+               const char *nname, const char *lxcpath, int snapshot)
+{
+       // use the 'zfs list | grep opath' entry to get the zfsroot
+       char output[MAXPATHLEN], option[MAXPATHLEN];
+       char *p;
+       const char *zfsroot = output;
+       int ret;
+       pid_t pid;
+
+       if (zfs_list_entry(opath, output, MAXPATHLEN)) {
+               // zfsroot is output up to ' '
+               if ((p = strchr(output, ' ')) == NULL)
+                       return -1;
+               *p = '\0';
+
+               if ((p = strrchr(output, '/')) == NULL)
+                       return -1;
+               *p = '\0';
+       } else {
+               zfsroot = lxc_global_config_value("lxc.bdev.zfs.root");
+       }
+
+       ret = snprintf(option, MAXPATHLEN, "-omountpoint=%s/%s/rootfs", lxcpath, nname);
+       if (ret < 0  || ret >= MAXPATHLEN)
+               return -1;
+
+       // zfs create -omountpoint=$lxcpath/$lxcname $zfsroot/$nname
+       if (!snapshot) {
+               if ((pid = fork()) < 0)
+                       return -1;
+               if (!pid) {
+                       char dev[MAXPATHLEN];
+                       ret = snprintf(dev, MAXPATHLEN, "%s/%s", zfsroot, nname);
+                       if (ret < 0  || ret >= MAXPATHLEN)
+                               exit(EXIT_FAILURE);
+                       execlp("zfs", "zfs", "create", option, dev, NULL);
+                       exit(EXIT_FAILURE);
+               }
+               return wait_for_pid(pid);
+       } else {
+               // if snapshot, do
+               // 'zfs snapshot zfsroot/oname@nname
+               // zfs clone zfsroot/oname@nname zfsroot/nname
+               char path1[MAXPATHLEN], path2[MAXPATHLEN];
+
+               ret = snprintf(path1, MAXPATHLEN, "%s/%s@%s", zfsroot,
+                               oname, nname);
+               if (ret < 0 || ret >= MAXPATHLEN)
+                       return -1;
+               (void) snprintf(path2, MAXPATHLEN, "%s/%s", zfsroot, nname);
+
+               // if the snapshot exists, delete it
+               if ((pid = fork()) < 0)
+                       return -1;
+               if (!pid) {
+                       execlp("zfs", "zfs", "destroy", path1, NULL);
+                       exit(EXIT_FAILURE);
+               }
+               // it probably doesn't exist so destroy probably will fail.
+               (void) wait_for_pid(pid);
+
+               // run first (snapshot) command
+               if ((pid = fork()) < 0)
+                       return -1;
+               if (!pid) {
+                       execlp("zfs", "zfs", "snapshot", path1, NULL);
+                       exit(EXIT_FAILURE);
+               }
+               if (wait_for_pid(pid) < 0)
+                       return -1;
+
+               // run second (clone) command
+               if ((pid = fork()) < 0)
+                       return -1;
+               if (!pid) {
+                       execlp("zfs", "zfs", "clone", option, path1, path2, NULL);
+                       exit(EXIT_FAILURE);
+               }
+               return wait_for_pid(pid);
+       }
+}
+
+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)
+{
+       int len, ret;
+
+       if (!orig->src || !orig->dest)
+               return -1;
+
+       if (snap && strcmp(orig->type, "zfs")) {
+               ERROR("zfs snapshot from %s backing store is not supported", orig->type);
+               return -1;
+       }
+
+       len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 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)
+               return -1;
+
+       if ((new->dest = strdup(new->src)) == NULL)
+               return -1;
+
+       return zfs_clone(orig->src, new->src, oldname, cname, lxcpath, snap);
+}
+
+/*
+ * TODO: detect whether this was a clone, and if so then also delete the
+ * snapshot it was based on, so that we don't hold the original
+ * container busy.
+ */
+int zfs_destroy(struct bdev *orig)
+{
+       pid_t pid;
+       char output[MAXPATHLEN];
+       char *p;
+
+       if ((pid = fork()) < 0)
+               return -1;
+       if (pid)
+               return wait_for_pid(pid);
+
+       if (!zfs_list_entry(orig->src, output, MAXPATHLEN)) {
+               ERROR("Error: zfs entry for %s not found", orig->src);
+               return -1;
+       }
+
+       // zfs mount is output up to ' '
+       if ((p = strchr(output, ' ')) == NULL)
+               return -1;
+       *p = '\0';
+
+       execlp("zfs", "zfs", "destroy", output, NULL);
+       exit(EXIT_FAILURE);
+}
+
+int zfs_create(struct bdev *bdev, const char *dest, const char *n,
+               struct bdev_specs *specs)
+{
+       const char *zfsroot;
+       char option[MAXPATHLEN];
+       int ret;
+       pid_t pid;
+
+       if (!specs || !specs->zfs.zfsroot)
+               zfsroot = lxc_global_config_value("lxc.bdev.zfs.root");
+       else
+               zfsroot = specs->zfs.zfsroot;
+
+       if (!(bdev->dest = strdup(dest))) {
+               ERROR("No mount target specified or out of memory");
+               return -1;
+       }
+       if (!(bdev->src = strdup(bdev->dest))) {
+               ERROR("out of memory");
+               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);
+
+       execlp("zfs", "zfs", "create", option, dev, NULL);
+       exit(EXIT_FAILURE);
+}
diff --git a/src/lxc/bdev/lxczfs.h b/src/lxc/bdev/lxczfs.h
new file mode 100644 (file)
index 0000000..0484619
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LXC_ZFS_H
+#define __LXC_ZFS_H
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdint.h>
+
+/* defined in bdev.h */
+struct bdev;
+
+/* defined in lxccontainer.h */
+struct bdev_specs;
+
+/* defined conf.h */
+struct lxc_conf;
+
+/*
+ * Functions associated with an zfs bdev struct.
+ */
+int zfs_clone(const char *opath, const char *npath, const char *oname,
+               const char *nname, const char *lxcpath, int snapshot);
+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);
+int zfs_create(struct bdev *bdev, const char *dest, const char *n,
+               struct bdev_specs *specs);
+/*
+ * TODO: detect whether this was a clone, and if so then also delete the
+ * snapshot it was based on, so that we don't hold the original
+ * container busy.
+ */
+int zfs_destroy(struct bdev *orig);
+int zfs_detect(const char *path);
+int zfs_list_entry(const char *path, char *output, size_t inlen);
+int zfs_mount(struct bdev *bdev);
+int zfs_umount(struct bdev *bdev);
+
+#endif /* __LXC_ZFS_H */