[libvirt] [PATCH 6/7] fspool: default implementation of filesystem pools

Nikolay Shirokovskiy nshirokovskiy at virtuozzo.com
Mon Jul 11 08:28:09 UTC 2016


From: Olga Krishtal <okrishtal at virtuozzo.com>

Implementation is backend base as in case of storage pools.
This patch adds directory backend which is nothing more
than managing directories inside another one as starting
point.

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy at virtuozzo.com>
---
 configure.ac             |   33 +
 daemon/Makefile.am       |    4 +
 po/POTFILES.in           |    2 +
 src/Makefile.am          |   38 +
 src/driver.h             |    1 +
 src/fs/fs_backend.h      |   85 ++
 src/fs/fs_backend_dir.c  |  334 +++++++
 src/fs/fs_backend_dir.h  |    8 +
 src/fs/fs_driver.c       | 2164 ++++++++++++++++++++++++++++++++++++++++++++++
 src/fs/fs_driver.h       |   10 +
 src/libvirt.c            |   28 +
 src/libvirt_private.syms |    1 +
 12 files changed, 2708 insertions(+)
 create mode 100644 src/fs/fs_backend.h
 create mode 100644 src/fs/fs_backend_dir.c
 create mode 100644 src/fs/fs_backend_dir.h
 create mode 100644 src/fs/fs_driver.c
 create mode 100644 src/fs/fs_driver.h

diff --git a/configure.ac b/configure.ac
index 2c81c95..36dc6b1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1647,6 +1647,35 @@ fi
 AM_CONDITIONAL([WITH_SECRETS], [test "$with_secrets" = "yes"])
 
 
+AC_ARG_WITH([fs-dir],
+  [AS_HELP_STRING([--with-fs-dir],
+    [with fs backend for fs driver @<:@default=yes@:>])],
+  [],[with_fs_dir=yes])
+
+if test "$with_libvirtd" = "no"; then
+  with_fs_dir=no
+fi
+
+if test "$with_fs_dir" = "yes" ; then
+  AC_DEFINE_UNQUOTED([WITH_FS_DIR], 1, [whether directory backend for fs driver is enabled])
+fi
+AM_CONDITIONAL([WITH_FS_DIR], [test "$with_fs_dir" = "yes"])
+
+with_fs=no
+for backend in dir; do
+    if eval test \$with_fs_$backend = yes; then
+        with_fs=yes
+        break
+    fi
+done
+if test $with_fs = yes; then
+    AC_DEFINE([WITH_FS], [1],
+      [Define to 1 if at least one fs backend is in use])
+fi
+AM_CONDITIONAL([WITH_FS], [test "$with_fs" = "yes"])
+
+
+
 AC_ARG_WITH([storage-dir],
   [AS_HELP_STRING([--with-storage-dir],
     [with directory backend for the storage driver @<:@default=yes@:>@])],
@@ -2760,6 +2789,10 @@ AC_MSG_NOTICE([Sheepdog: $with_storage_sheepdog])
 AC_MSG_NOTICE([ Gluster: $with_storage_gluster])
 AC_MSG_NOTICE([     ZFS: $with_storage_zfs])
 AC_MSG_NOTICE([])
+AC_MSG_NOTICE([Fs Drivers])
+AC_MSG_NOTICE([])
+AC_MSG_NOTICE([     Dir: $with_fs_dir])
+AC_MSG_NOTICE([])
 AC_MSG_NOTICE([Security Drivers])
 AC_MSG_NOTICE([])
 AC_MSG_NOTICE([ SELinux: $with_secdriver_selinux ($SELINUX_MOUNT)])
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 927d16f..63444cf 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -241,6 +241,10 @@ if WITH_STORAGE
     libvirtd_LDADD += ../src/libvirt_driver_storage.la
 endif WITH_STORAGE
 
+if WITH_FS
+    libvirtd_LDADD += ../src/libvirt_driver_fs.la
+endif WITH_FS
+
 if WITH_NETWORK
     libvirtd_LDADD += ../src/libvirt_driver_network.la
 endif WITH_NETWORK
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 313edf2..8b3cfd5 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -57,6 +57,8 @@ src/esx/esx_vi.c
 src/esx/esx_vi_methods.c
 src/esx/esx_vi_types.c
 src/fdstream.c
+src/fs/fs_backend_dir.c
+src/fs/fs_driver.c
 src/hyperv/hyperv_driver.c
 src/hyperv/hyperv_util.c
 src/hyperv/hyperv_wmi.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 77e64f4..768e4a7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -638,6 +638,7 @@ DRIVER_SOURCE_FILES = \
 	$(REMOTE_DRIVER_SOURCES) \
 	$(SECRET_DRIVER_SOURCES) \
 	$(STORAGE_DRIVER_SOURCES) \
+	$(FS_DRIVER_SOURCES) \
 	$(TEST_DRIVER_SOURCES) \
 	$(UML_DRIVER_SOURCES) \
 	$(VBOX_DRIVER_SOURCES) \
@@ -658,6 +659,7 @@ STATEFUL_DRIVER_SOURCE_FILES = \
 	$(QEMU_DRIVER_SOURCES) \
 	$(SECRET_DRIVER_SOURCES) \
 	$(STORAGE_DRIVER_SOURCES) \
+	$(FS_DRIVER_SOURCES) \
 	$(UML_DRIVER_SOURCES) \
 	$(XEN_DRIVER_SOURCES) \
 	$(NULL)
@@ -962,6 +964,14 @@ SECRET_UTIL_SOURCES =						\
 SECRET_DRIVER_SOURCES =						\
 		secret/secret_driver.h secret/secret_driver.c
 
+# FS pool backend specific impls
+FS_DRIVER_SOURCES =							\
+		fs/fs_driver.h fs/fs_driver.c		\
+		fs/fs_backend.h
+
+FS_DRIVER_DIR_SOURCES =							\
+		fs/fs_backend_dir.h fs/fs_backend_dir.c
+
 # Storage backend specific impls
 STORAGE_DRIVER_SOURCES =						\
 		storage/storage_driver.h storage/storage_driver.c	\
@@ -1625,6 +1635,32 @@ endif WITH_DRIVER_MODULES
 libvirt_driver_secret_la_SOURCES = $(SECRET_DRIVER_SOURCES)
 endif WITH_SECRETS
 
+libvirt_driver_fs_impl_la_SOURCES =
+libvirt_driver_fs_impl_la_CFLAGS = \
+		-I$(srcdir)/access \
+		-I$(srcdir)/conf \
+		$(AM_CFLAGS)
+libvirt_driver_fs_impl_la_LDFLAGS = $(AM_LDFLAGS)
+libvirt_driver_fs_impl_la_LIBADD =
+libvirt_driver_fs_impl_la_LIBADD += $(SECDRIVER_LIBS) $(LIBXML_LIBS)
+if WITH_FS
+noinst_LTLIBRARIES += libvirt_driver_fs_impl.la
+libvirt_driver_fs_la_SOURCES =
+libvirt_driver_fs_la_LIBADD = libvirt_driver_fs_impl.la
+if WITH_DRIVER_MODULES
+mod_LTLIBRARIES += libvirt_driver_fs.la
+libvirt_driver_fs_la_LIBADD += ../gnulib/lib/libgnu.la
+libvirt_driver_fs_la_LDFLAGS = -module -avoid-version $(AM_LDFLAGS)
+else ! WITH_DRIVER_MODULES
+noinst_LTLIBRARIES += libvirt_driver_fs.la
+# Stateful, so linked to daemon instead
+#libvirt_la_BUILT_LIBADD += libvirt_driver_fs.la
+endif ! WITH_DRIVER_MODULES
+libvirt_driver_fs_impl_la_SOURCES += $(FS_DRIVER_SOURCES)
+libvirt_driver_fs_impl_la_SOURCES += $(FS_DRIVER_DIR_SOURCES)
+endif WITH_FS
+
+
 # Needed to keep automake quiet about conditionals
 libvirt_driver_storage_impl_la_SOURCES =
 libvirt_driver_storage_impl_la_CFLAGS = \
@@ -1896,6 +1932,8 @@ EXTRA_DIST +=							\
 		$(BHYVE_DRIVER_SOURCES)				\
 		$(NETWORK_DRIVER_SOURCES)			\
 		$(INTERFACE_DRIVER_SOURCES)			\
+		$(FS_DRIVER_SOURCES)				\
+		$(FS_DRIVER_DIR_SOURCES)			\
 		$(STORAGE_DRIVER_SOURCES)			\
 		$(STORAGE_DRIVER_FS_SOURCES)			\
 		$(STORAGE_DRIVER_LVM_SOURCES)			\
diff --git a/src/driver.h b/src/driver.h
index 57ad1f7..6d475f9 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -100,6 +100,7 @@ int virSetSharedNodeDeviceDriver(virNodeDeviceDriverPtr driver) ATTRIBUTE_RETURN
 int virSetSharedNWFilterDriver(virNWFilterDriverPtr driver) ATTRIBUTE_RETURN_CHECK;
 int virSetSharedSecretDriver(virSecretDriverPtr driver) ATTRIBUTE_RETURN_CHECK;
 int virSetSharedStorageDriver(virStorageDriverPtr driver) ATTRIBUTE_RETURN_CHECK;
+int virSetSharedFsDriver(virFsDriverPtr driver) ATTRIBUTE_RETURN_CHECK;
 
 void *virDriverLoadModule(const char *name);
 
diff --git a/src/fs/fs_backend.h b/src/fs/fs_backend.h
new file mode 100644
index 0000000..f714b29
--- /dev/null
+++ b/src/fs/fs_backend.h
@@ -0,0 +1,85 @@
+#ifndef __VIR_FS_BACKEND_H__
+# define __VIR_FS_BACKEND_H__
+
+# include <sys/stat.h>
+
+# include "internal.h"
+# include "fs_conf.h"
+# include "fs_driver.h"
+
+typedef char * (*virFsBackendFindFspoolSources)(virConnectPtr conn,
+                                                const char *srcSpec,
+                                                unsigned int flags);
+typedef int (*virFsBackendCheckFspool)(virFsPoolObjPtr fspool,
+                                       bool *active);
+typedef int (*virFsBackendStartFspool)(virConnectPtr conn,
+                                      virFsPoolObjPtr fspool);
+typedef int (*virFsBackendBuildFspool)(virConnectPtr conn,
+                                       virFsPoolObjPtr fspool,
+                                       unsigned int flags);
+typedef int (*virFsBackendRefreshFspool)(virConnectPtr conn,
+                                         virFsPoolObjPtr fspool);
+typedef int (*virFsBackendStopFspool)(virConnectPtr conn,
+                                       virFsPoolObjPtr fspool);
+typedef int (*virFsBackendDeleteFspool)(virConnectPtr conn,
+                                        virFsPoolObjPtr fspool,
+                                        unsigned int flags);
+
+/* FIXME */
+
+/* A 'buildItem' backend must remove any volume created on error since
+ * the storage driver does not distinguish whether the failure is due
+ * to failure to create the volume, to reserve any space necessary for
+ * the volume, to get data about the volume, to change it's accessibility,
+ * etc. This avoids issues arising from a creation failure due to some
+ * external action which created a volume of the same name that libvirt
+ * was not aware of between checking the fspool and the create attempt. It
+ * also avoids extra round trips to just delete a file.
+ */
+typedef int (*virFsBackendBuildItem)(virConnectPtr conn,
+                                     virFsPoolObjPtr fspool,
+                                     virFsItemDefPtr item,
+                                     unsigned int flags);
+typedef int (*virFsBackendCreateItem)(virConnectPtr conn,
+                                      virFsPoolObjPtr fspool,
+                                      virFsItemDefPtr item);
+typedef int (*virFsBackendRefreshItem)(virConnectPtr conn,
+                                       virFsPoolObjPtr fspool,
+                                       virFsItemDefPtr item);
+typedef int (*virFsBackendDeleteItem)(virConnectPtr conn,
+                                      virFsPoolObjPtr fspool,
+                                      virFsItemDefPtr item,
+                                      unsigned int flags);
+typedef int (*virFsBackendBuildItemFrom)(virConnectPtr conn,
+                                         virFsPoolObjPtr fspool,
+                                         virFsItemDefPtr origitem,
+                                         virFsItemDefPtr newitem,
+                                         unsigned int flags);
+
+typedef struct _virFsBackend virFsBackend;
+typedef virFsBackend *virFsBackendPtr;
+
+/* Callbacks are optional unless documented otherwise; but adding more
+ * callbacks provides better fspool support.  */
+struct _virFsBackend {
+    int type;
+
+    virFsBackendFindFspoolSources findFspoolSources;
+    virFsBackendCheckFspool checkFspool;
+    virFsBackendStartFspool startFspool;
+    virFsBackendBuildFspool buildFspool;
+    virFsBackendRefreshFspool refreshFspool; /* Must be non-NULL */
+    virFsBackendStopFspool stopFspool;
+    virFsBackendDeleteFspool deleteFspool;
+
+    virFsBackendBuildItem buildItem;
+    virFsBackendBuildItemFrom buildItemFrom;
+    virFsBackendCreateItem createItem;
+    virFsBackendRefreshItem refreshItem;
+    virFsBackendDeleteItem deleteItem;
+};
+
+# define VIR_FS_DEFAULT_POOL_PERM_MODE 0755
+# define VIR_FS_DEFAULT_ITEM_PERM_MODE  0600
+
+#endif /* __VIR_FS_BACKEND_H__ */
diff --git a/src/fs/fs_backend_dir.c b/src/fs/fs_backend_dir.c
new file mode 100644
index 0000000..fc08b85
--- /dev/null
+++ b/src/fs/fs_backend_dir.c
@@ -0,0 +1,334 @@
+#include <config.h>
+
+#include <sys/statvfs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+
+#include "virerror.h"
+#include "fs_backend_dir.h"
+#include "fs_conf.h"
+#include "vircommand.h"
+#include "viralloc.h"
+#include "virxml.h"
+#include "virfile.h"
+#include "virlog.h"
+#include "virstring.h"
+#include "fdstream.h"
+#include "stat-time.h"
+
+#define VIR_FROM_THIS VIR_FROM_FSPOOL
+
+VIR_LOG_INIT("fs.fs_backend_dir");
+
+static int
+virFsDirBuild(virConnectPtr conn ATTRIBUTE_UNUSED,
+              virFsPoolObjPtr fspool,
+              unsigned int flags)
+{
+    int ret = -1;
+    char *parent = NULL;
+    char *p = NULL;
+    mode_t mode;
+    unsigned int dir_create_flags;
+
+    virCheckFlags(0, -1);
+
+    if (VIR_STRDUP(parent, fspool->def->target.path) < 0)
+        goto error;
+    if (!(p = strrchr(parent, '/'))) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("path '%s' is not absolute"),
+                       fspool->def->target.path);
+        goto error;
+    }
+
+    if (p != parent) {
+        /* assure all directories in the path prior to the final dir
+         * exist, with default uid/gid/mode. */
+        *p = '\0';
+        if (virFileMakePath(parent) < 0) {
+            virReportSystemError(errno, _("cannot create path '%s'"),
+                                 parent);
+            goto error;
+        }
+    }
+
+    dir_create_flags = VIR_DIR_CREATE_ALLOW_EXIST;
+    mode = fspool->def->target.perms.mode;
+
+    if (mode == (mode_t) -1 &&
+        (!virFileExists(fspool->def->target.path)))
+        mode = VIR_FS_DEFAULT_POOL_PERM_MODE;
+
+    /* Now create the final dir in the path with the uid/gid/mode
+     * requested in the config. If the dir already exists, just set
+     * the perms. */
+    if (virDirCreate(fspool->def->target.path,
+                     mode,
+                     fspool->def->target.perms.uid,
+                     fspool->def->target.perms.gid,
+                     dir_create_flags) < 0)
+        goto error;
+
+    ret = 0;
+
+ error:
+    VIR_FREE(parent);
+    return ret;
+}
+
+static int
+virFsDirRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
+                virFsPoolObjPtr fspool)
+{
+    DIR *dir;
+    struct dirent *entry;
+    virFsItemDefPtr item = NULL;
+    struct statvfs sb;
+    struct stat statbuf;
+    int fd = 0;
+    int ret = -1;
+
+    if (virDirOpen(&dir, fspool->def->target.path) < 0)
+        goto cleanup;
+
+    while (virDirRead(dir, &entry, fspool->def->target.path) > 0) {
+        if (virStringHasControlChars(entry->d_name)) {
+            VIR_WARN("Ignoring control characters under '%s'",
+                     fspool->def->target.path);
+            continue;
+        }
+
+        if (VIR_ALLOC(item) < 0)
+            goto cleanup;
+
+        if (VIR_STRDUP(item->name, entry->d_name) < 0)
+            goto cleanup;
+        item->type  = VIR_FS_ITEM_DIR;
+        if (virAsprintf(&item->target.path, "%s/%s",
+                        fspool->def->target.path,
+                        item->name) == -1)
+            goto cleanup;
+
+        if (VIR_STRDUP(item->key, item->target.path) < 0)
+            goto cleanup;
+
+
+        if (VIR_APPEND_ELEMENT(fspool->items.objs, fspool->items.count, item) < 0)
+            goto cleanup;
+    }
+
+
+    if ((fd = open(fspool->def->target.path, O_RDONLY)) < 0) {
+        virReportSystemError(errno,
+                             _("cannot open path '%s'"),
+                             fspool->def->target.path);
+        goto cleanup;
+    }
+
+    if (fstat(fd, &statbuf) < 0) {
+        virReportSystemError(errno,
+                             _("cannot stat path '%s'"),
+                             fspool->def->target.path);
+        goto cleanup;
+    }
+
+    fspool->def->target.perms.mode = statbuf.st_mode & S_IRWXUGO;
+    fspool->def->target.perms.uid = statbuf.st_uid;
+    fspool->def->target.perms.gid = statbuf.st_gid;
+
+    if (statvfs(fspool->def->target.path, &sb) < 0) {
+        virReportSystemError(errno,
+                             _("cannot statvfs path '%s'"),
+                             fspool->def->target.path);
+        goto cleanup;
+    }
+
+    fspool->def->capacity = ((unsigned long long)sb.f_blocks *
+                           (unsigned long long)sb.f_frsize);
+    fspool->def->available = ((unsigned long long)sb.f_bfree *
+                            (unsigned long long)sb.f_frsize);
+    fspool->def->allocation = fspool->def->capacity - fspool->def->available;
+
+    ret = 0;
+
+ cleanup:
+    VIR_DIR_CLOSE(dir);
+    VIR_FORCE_CLOSE(fd);
+    virFsItemDefFree(item);
+    if (ret < 0)
+        virFsPoolObjClearItems(fspool);
+    return ret;
+}
+
+static int
+virFsDirDelete(virConnectPtr conn ATTRIBUTE_UNUSED,
+               virFsPoolObjPtr fspool,
+               unsigned int flags)
+{
+    virCheckFlags(0, -1);
+
+    if (rmdir(fspool->def->target.path) < 0) {
+        virReportSystemError(errno, _("failed to remove fspool '%s'"),
+                             fspool->def->target.path);
+        return -1;
+    }
+
+    return 0;
+
+}
+static int
+virFsDirItemBuild(virConnectPtr conn ATTRIBUTE_UNUSED,
+                  virFsPoolObjPtr fspool ATTRIBUTE_UNUSED,
+                  virFsItemDefPtr item,
+                  unsigned int flags)
+{
+    virCheckFlags(0, -1);
+
+    if (item->type == VIR_FS_ITEM_DIR) {
+        if ((virDirCreate(item->target.path,
+                          (item->target.perms->mode == (mode_t) -1 ?
+                           VIR_FS_DEFAULT_ITEM_PERM_MODE:
+                           item->target.perms->mode),
+                          item->target.perms->uid,
+                          item->target.perms->gid,
+                          0)) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("error creating item"));
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int
+virFsDirItemBuildFrom(virConnectPtr conn ATTRIBUTE_UNUSED,
+                      virFsPoolObjPtr fspool ATTRIBUTE_UNUSED,
+                      virFsItemDefPtr item,
+                      virFsItemDefPtr inputitem,
+                      unsigned int flags)
+{
+    virCommandPtr cmd = NULL;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    item->target.capacity = inputitem->target.capacity;
+    cmd = virCommandNewArgList("cp", "-r", inputitem->target.path,
+                               item->target.path, NULL);
+    ret = virCommandRun(cmd, NULL);
+
+    virCommandFree(cmd);
+    return ret;
+}
+
+static int
+virFsDirItemCreate(virConnectPtr conn ATTRIBUTE_UNUSED,
+                   virFsPoolObjPtr fspool,
+                   virFsItemDefPtr item)
+{
+    if (strchr(item->name, '/')) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("volume name '%s' cannot contain '/'"), item->name);
+        return -1;
+    }
+
+    VIR_FREE(item->target.path);
+    if (virAsprintf(&item->target.path, "%s/%s",
+                    fspool->def->target.path,
+                    item->name) == -1)
+        return -1;
+
+    if (virFileExists(item->target.path)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("item target path '%s' already exists"),
+                       item->target.path);
+        return -1;
+    }
+
+    VIR_FREE(item->key);
+    return VIR_STRDUP(item->key, item->target.path);
+}
+
+
+static int
+virFsDirItemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
+                    virFsPoolObjPtr fspool ATTRIBUTE_UNUSED,
+                    virFsItemDefPtr item)
+{
+    int fd;
+    int ret = -1;
+    struct stat statbuf;
+    virCommandPtr cmd = NULL;
+    char *output = NULL, *end;
+
+    if ((fd = open(item->target.path, O_RDONLY)) < 0) {
+        virReportSystemError(errno, _("cannot open directory '%s'"),
+                             item->target.path);
+        return -1;
+    }
+    if (fstat(fd, &statbuf) < 0) {
+         virReportSystemError(errno, _("cannot stat path '%s'"),
+                             item->target.path);
+        goto cleanup;
+    }
+
+    cmd = virCommandNewArgList("du", "-sB1", item->target.path, NULL);
+    virCommandSetOutputBuffer(cmd, &output);
+    if ((ret = virCommandRun(cmd, NULL)) < 0)
+        goto cleanup;
+
+    if (virStrToLong_ull(output, &end, 10, &item->target.allocation) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Malformed du output: %s"), output);
+        goto cleanup;
+    }
+
+    if (&(item->target.perms) && VIR_ALLOC(*(&item->target.perms)) < 0)
+            goto cleanup;
+    item->target.perms->mode = statbuf.st_mode & S_IRWXUGO;
+    item->target.perms->uid = statbuf.st_uid;
+    item->target.perms->gid = statbuf.st_gid;
+
+    ret = 0;
+ cleanup:
+    VIR_FORCE_CLOSE(fd);
+    VIR_FREE(output);
+    virCommandFree(cmd);
+    return ret;
+}
+
+static int
+virFsDirItemDelete(virConnectPtr conn ATTRIBUTE_UNUSED,
+                   virFsPoolObjPtr fspool ATTRIBUTE_UNUSED,
+                   virFsItemDefPtr item,
+                   unsigned int flags)
+{
+    virCheckFlags(0, -1);
+
+    return virFileDeleteTree(item->target.path);
+}
+
+virFsBackend virFsBackendDir = {
+    .type = VIR_FS_POOL_DIR,
+
+    .buildFspool = virFsDirBuild,
+    .refreshFspool = virFsDirRefresh,
+    .deleteFspool = virFsDirDelete,
+    .buildItem = virFsDirItemBuild,
+    .buildItemFrom = virFsDirItemBuildFrom,
+    .createItem = virFsDirItemCreate,
+    .deleteItem = virFsDirItemDelete,
+    .refreshItem = virFsDirItemRefresh,
+};
diff --git a/src/fs/fs_backend_dir.h b/src/fs/fs_backend_dir.h
new file mode 100644
index 0000000..d8ff68f
--- /dev/null
+++ b/src/fs/fs_backend_dir.h
@@ -0,0 +1,8 @@
+#ifndef __VIR_FS_BACKEND_DIR_H__
+# define __VIR_FS_BACKEND_DIR_H__
+
+# include "fs_backend.h"
+
+extern virFsBackend virFsBackendDir;
+
+#endif /* __VIR_FS_BACKEND_DIR_H__ */
diff --git a/src/fs/fs_driver.c b/src/fs/fs_driver.c
new file mode 100644
index 0000000..76aba7a
--- /dev/null
+++ b/src/fs/fs_driver.c
@@ -0,0 +1,2164 @@
+#include <config.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <fcntl.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "driver.h"
+#include "fs_driver.h"
+#include "fs_conf.h"
+#include "fs_backend.h"
+#include "viralloc.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "fdstream.h"
+#include "configmake.h"
+#include "virstring.h"
+#include "viraccessapicheck.h"
+#include "dirname.h"
+
+#if WITH_FS_DIR
+# include "fs_backend_dir.h"
+#endif
+
+#define VIR_FROM_THIS VIR_FROM_FSPOOL
+
+VIR_LOG_INIT("fs.fs_driver");
+
+static virFsDriverStatePtr driver;
+
+typedef struct _virFsItemStreamInfo virFsItemStreamInfo;
+typedef virFsItemStreamInfo *virFsItemStreamInfoPtr;
+struct _virFsItemStreamInfo {
+    char *fspool_name;
+    char *item_path;
+};
+
+static int fsStateCleanup(void);
+
+static void fsDriverLock(void)
+{
+    virMutexLock(&driver->lock);
+}
+
+static void fsDriverUnlock(void)
+{
+    virMutexUnlock(&driver->lock);
+}
+
+static virFsBackendPtr backends[] = {
+#if WITH_FS_DIR
+    &virFsBackendDir,
+#endif
+};
+
+static virFsBackendPtr
+virFsBackendForType(int type)
+{
+    size_t i;
+    for (i = 0; backends[i]; i++)
+        if (backends[i]->type == type)
+            return backends[i];
+
+    virReportError(VIR_ERR_INTERNAL_ERROR,
+                   _("missing backend for fspool type %d (%s)"),
+                   type, NULLSTR(virFsPoolTypeToString(type)));
+    return NULL;
+}
+
+static void
+fsItemRemoveFromFsPool(virFsPoolObjPtr fspool,
+                       virFsItemDefPtr item)
+{
+    size_t i;
+
+    for (i = 0; i < fspool->items.count; i++) {
+        if (fspool->items.objs[i] == item) {
+            VIR_INFO("Deleting item '%s' from fspool '%s'",
+                     item->name, fspool->def->name);
+            virFsItemDefFree(item);
+
+            VIR_DELETE_ELEMENT(fspool->items.objs, i, fspool->items.count);
+            break;
+        }
+    }
+}
+
+static int
+fsItemDeleteInternal(virFsItemPtr obj,
+                     virFsBackendPtr backend,
+                     virFsPoolObjPtr fspool,
+                     virFsItemDefPtr item,
+                     unsigned int flags)
+{
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    if (!backend->deleteItem) {
+        virReportError(VIR_ERR_NO_SUPPORT,
+                  "%s", _("fspool does not support item deletion"));
+        goto cleanup;
+    }
+    if (backend->deleteItem(obj->conn, fspool, item, flags) < 0)
+        goto cleanup;
+
+    fsItemRemoveFromFsPool(fspool, item);
+
+    ret = 0;
+
+ cleanup:
+    return ret;
+}
+
+static virFsItemDefPtr
+virFsItemDefFromItem(virFsItemPtr obj,
+                     virFsPoolObjPtr *fspool,
+                     virFsBackendPtr *backend)
+{
+    virFsItemDefPtr item = NULL;
+
+    *fspool = NULL;
+
+    fsDriverLock();
+    *fspool = virFsPoolObjFindByName(&driver->fspools, obj->fspool);
+    fsDriverUnlock();
+
+    if (!*fspool) {
+        virReportError(VIR_ERR_NO_FS_POOL,
+                       _("no fspool with matching name '%s'"),
+                       obj->fspool);
+        return NULL;
+    }
+
+    if (!virFsPoolObjIsActive(*fspool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("fspool '%s' is not active"),
+                       (*fspool)->def->name);
+        goto error;
+    }
+
+    if (!(item = virFsItemDefFindByName(*fspool, obj->name))) {
+        virReportError(VIR_ERR_NO_FS_ITEM,
+                       _("no fs item with matching name '%s'"),
+                       obj->name);
+        goto error;
+    }
+
+    if (backend) {
+        if (!(*backend = virFsBackendForType((*fspool)->def->type)))
+            goto error;
+    }
+
+    return item;
+
+ error:
+    virFsPoolObjUnlock(*fspool);
+    *fspool = NULL;
+
+    return NULL;
+}
+
+static void
+fsPoolUpdateState(virFsPoolObjPtr fspool)
+{
+    bool active;
+    virFsBackendPtr backend;
+    int ret = -1;
+    char *stateFile;
+
+    if (!(stateFile = virFileBuildPath(driver->stateDir,
+                                       fspool->def->name, ".xml")))
+        goto error;
+
+    if ((backend = virFsBackendForType(fspool->def->type)) == NULL) {
+        VIR_ERROR(_("Missing backend %d"), fspool->def->type);
+        goto error;
+    }
+
+    /* Backends which do not support 'checkFspool' are considered
+     * inactive by default.
+     */
+    active = false;
+    if (backend->checkFspool &&
+        backend->checkFspool(fspool, &active) < 0) {
+        virErrorPtr err = virGetLastError();
+        VIR_ERROR(_("Failed to initialize fspool '%s': %s"),
+                  fspool->def->name, err ? err->message :
+                  _("no error message found"));
+        goto error;
+    }
+
+    /* We can pass NULL as connection, most backends do not use
+     * it anyway, but if they do and fail, we want to log error and
+     * continue with other fspools.
+     */
+    if (active) {
+        virFsPoolObjClearItems(fspool);
+        if (backend->refreshFspool(NULL, fspool) < 0) {
+            virErrorPtr err = virGetLastError();
+            if (backend->stopFspool)
+                backend->stopFspool(NULL, fspool);
+            VIR_ERROR(_("Failed to restart fspool '%s': %s"),
+                      fspool->def->name, err ? err->message :
+                      _("no error message found"));
+            goto error;
+        }
+    }
+
+    fspool->active = active;
+    ret = 0;
+ error:
+    if (ret < 0) {
+        if (stateFile)
+            unlink(stateFile);
+    }
+    VIR_FREE(stateFile);
+
+    return;
+}
+
+static void
+fsPoolUpdateAllState(void)
+{
+    size_t i;
+
+    for (i = 0; i < driver->fspools.count; i++) {
+        virFsPoolObjPtr fspool = driver->fspools.objs[i];
+
+        virFsPoolObjLock(fspool);
+        fsPoolUpdateState(fspool);
+        virFsPoolObjUnlock(fspool);
+    }
+}
+
+static void
+fsDriverAutostart(void)
+{
+    size_t i;
+    virConnectPtr conn = NULL;
+
+    /* XXX Remove hardcoding of QEMU URI */
+    if (driver->privileged)
+        conn = virConnectOpen("qemu:///system");
+    else
+        conn = virConnectOpen("qemu:///session");
+    /* Ignoring NULL conn - let backends decide */
+
+   for (i = 0; i < driver->fspools.count; i++) {
+        virFsPoolObjPtr fspool = driver->fspools.objs[i];
+        virFsBackendPtr backend;
+        bool started = false;
+
+        virFsPoolObjLock(fspool);
+        if ((backend = virFsBackendForType(fspool->def->type)) == NULL) {
+            virFsPoolObjUnlock(fspool);
+            continue;
+        }
+
+        if (fspool->autostart &&
+            !virFsPoolObjIsActive(fspool)) {
+            if (backend->startFspool &&
+                backend->startFspool(conn, fspool) < 0) {
+                virErrorPtr err = virGetLastError();
+                VIR_ERROR(_("Failed to autostart fspool '%s': %s"),
+                          fspool->def->name, err ? err->message :
+                          _("no error message found"));
+                virFsPoolObjUnlock(fspool);
+                continue;
+            }
+            started = true;
+        }
+
+        if (started) {
+            char *stateFile;
+
+            virFsPoolObjClearItems(fspool);
+            stateFile = virFileBuildPath(driver->stateDir,
+                                         fspool->def->name, ".xml");
+            if (!stateFile ||
+                virFsPoolSaveState(stateFile, fspool->def) < 0 ||
+                backend->refreshFspool(conn, fspool) < 0) {
+                virErrorPtr err = virGetLastError();
+                if (stateFile)
+                    unlink(stateFile);
+                if (backend->stopFspool)
+                    backend->stopFspool(conn, fspool);
+                VIR_ERROR(_("Failed to autostart fspool '%s': %s"),
+                          fspool->def->name, err ? err->message :
+                          _("no error message found"));
+            } else {
+                fspool->active = true;
+            }
+            VIR_FREE(stateFile);
+        }
+        virFsPoolObjUnlock(fspool);
+    }
+
+    virObjectUnref(conn);
+}
+
+/**
+ * virFsStartup:
+ *
+ * Initialization function for the Fs Driver
+ */
+static int
+fsStateInitialize(bool privileged,
+                  virStateInhibitCallback callback ATTRIBUTE_UNUSED,
+                  void *opaque ATTRIBUTE_UNUSED)
+{
+    int ret = -1;
+    char *configdir = NULL;
+    char *rundir = NULL;
+
+    if (VIR_ALLOC(driver) < 0)
+        return ret;
+
+    if (virMutexInit(&driver->lock) < 0) {
+        VIR_FREE(driver);
+        return ret;
+    }
+    fsDriverLock();
+
+    if (privileged) {
+        if (VIR_STRDUP(driver->configDir,
+                       SYSCONFDIR "/libvirt/fs") < 0 ||
+            VIR_STRDUP(driver->autostartDir,
+                       SYSCONFDIR "/libvirt/fs/autostart") < 0 ||
+            VIR_STRDUP(driver->stateDir,
+                       LOCALSTATEDIR "/run/libvirt/fs") < 0)
+            goto error;
+    } else {
+        configdir = virGetUserConfigDirectory();
+        rundir = virGetUserRuntimeDirectory();
+        if (!(configdir && rundir))
+            goto error;
+
+        if ((virAsprintf(&driver->configDir,
+                        "%s/fs", configdir) < 0) ||
+            (virAsprintf(&driver->autostartDir,
+                        "%s/fs/autostart", configdir) < 0) ||
+            (virAsprintf(&driver->stateDir,
+                         "%s/fs/run", rundir) < 0))
+            goto error;
+    }
+    driver->privileged = privileged;
+
+    if (virFileMakePath(driver->stateDir) < 0) {
+        virReportError(errno,
+                       _("cannot create directory %s"),
+                       driver->stateDir);
+        goto error;
+    }
+
+    if (virFsPoolLoadAllState(&driver->fspools,
+                                   driver->stateDir) < 0)
+        goto error;
+
+    if (virFsPoolLoadAllConfigs(&driver->fspools,
+                                     driver->configDir,
+                                     driver->autostartDir) < 0)
+        goto error;
+
+    fsPoolUpdateAllState();
+
+    fsDriverUnlock();
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(configdir);
+    VIR_FREE(rundir);
+    return ret;
+
+ error:
+    fsDriverUnlock();
+    fsStateCleanup();
+    goto cleanup;
+}
+
+/**
+ * fsStateAutoStart:
+ *
+ * Function to auto start the fs_driver
+ */
+static void
+fsStateAutoStart(void)
+{
+    if (!driver)
+        return;
+
+    fsDriverLock();
+    fsDriverAutostart();
+    fsDriverUnlock();
+}
+
+/**
+ * fsStateReload:
+ *
+ * Function to restart the fs_driver, it will recheck the configuration
+ * files and update its state
+ */
+static int
+fsStateReload(void)
+{
+    if (!driver)
+        return -1;
+
+    fsDriverLock();
+    virFsPoolLoadAllState(&driver->fspools,
+                          driver->stateDir);
+    virFsPoolLoadAllConfigs(&driver->fspools,
+                            driver->configDir,
+                            driver->autostartDir);
+    fsDriverAutostart();
+    fsDriverUnlock();
+
+    return 0;
+}
+
+
+/**
+ * fsStateCleanup
+ *
+ * Shutdown the fs driver, it will stop all active fspools
+ */
+static int
+fsStateCleanup(void)
+{
+    if (!driver)
+        return -1;
+
+    fsDriverLock();
+
+    /* free inactive fspools */
+    virFsPoolObjListFree(&driver->fspools);
+
+    VIR_FREE(driver->configDir);
+    VIR_FREE(driver->autostartDir);
+    VIR_FREE(driver->stateDir);
+    fsDriverUnlock();
+    virMutexDestroy(&driver->lock);
+    VIR_FREE(driver);
+
+    return 0;
+}
+
+
+static virFsPoolObjPtr
+virFsPoolObjFromFsPool(virFsPoolPtr fspool)
+{
+    char uuidstr[VIR_UUID_STRING_BUFLEN];
+    virFsPoolObjPtr ret;
+
+    fsDriverLock();
+    if (!(ret = virFsPoolObjFindByUUID(&driver->fspools, fspool->uuid))) {
+        virUUIDFormat(fspool->uuid, uuidstr);
+        virReportError(VIR_ERR_NO_FS_POOL,
+                       _("no fspool with matching uuid '%s' (%s)"),
+                       uuidstr, fspool->name);
+    }
+    fsDriverUnlock();
+
+    return ret;
+}
+
+static int
+fsConnectNumOfFsPools(virConnectPtr conn)
+{
+    size_t i;
+    int nactive = 0;
+
+    if (virConnectNumOfFsPoolsEnsureACL(conn) < 0)
+        return -1;
+
+    fsDriverLock();
+    for (i = 0; i < driver->fspools.count; i++) {
+        virFsPoolObjPtr obj = driver->fspools.objs[i];
+        virFsPoolObjLock(obj);
+        if (virConnectNumOfFsPoolsCheckACL(conn, obj->def) &&
+            virFsPoolObjIsActive(obj))
+            nactive++;
+        virFsPoolObjUnlock(obj);
+    }
+    fsDriverUnlock();
+
+    return nactive;
+}
+
+static int
+fsConnectListAllFsPools(virConnectPtr conn,
+                        virFsPoolPtr **fspools,
+                        unsigned int flags)
+{
+    int ret = -1;
+
+    virCheckFlags(VIR_CONNECT_LIST_FS_POOLS_FILTERS_ALL, -1);
+
+    if (virConnectListAllFsPoolsEnsureACL(conn) < 0)
+        goto cleanup;
+
+    fsDriverLock();
+    ret = virFsPoolObjListExport(conn, driver->fspools, fspools,
+                                 virConnectListAllFsPoolsCheckACL,
+                                 flags);
+    fsDriverUnlock();
+
+ cleanup:
+    return ret;
+}
+
+static int
+fsConnectListFsPools(virConnectPtr conn,
+                     char **const names,
+                     int nnames)
+{
+    int got = 0;
+    size_t i;
+
+    if (virConnectListFsPoolsEnsureACL(conn) < 0)
+        return -1;
+
+    fsDriverLock();
+    for (i = 0; i < driver->fspools.count && got < nnames; i++) {
+        virFsPoolObjPtr obj = driver->fspools.objs[i];
+        virFsPoolObjLock(obj);
+        if (virConnectListFsPoolsCheckACL(conn, obj->def) &&
+            virFsPoolObjIsActive(obj)) {
+            if (VIR_STRDUP(names[got], obj->def->name) < 0) {
+                virFsPoolObjUnlock(obj);
+                goto cleanup;
+            }
+            got++;
+        }
+        virFsPoolObjUnlock(obj);
+    }
+    fsDriverUnlock();
+    return got;
+
+ cleanup:
+    fsDriverUnlock();
+    for (i = 0; i < got; i++)
+        VIR_FREE(names[i]);
+    memset(names, 0, nnames * sizeof(*names));
+    return -1;
+}
+
+static int
+fsConnectNumOfDefinedFsPools(virConnectPtr conn)
+{
+    size_t i;
+    int nactive = 0;
+
+    if (virConnectNumOfDefinedFsPoolsEnsureACL(conn) < 0)
+        return -1;
+
+    fsDriverLock();
+    for (i = 0; i < driver->fspools.count; i++) {
+        virFsPoolObjPtr obj = driver->fspools.objs[i];
+        virFsPoolObjLock(obj);
+        if (virConnectNumOfDefinedFsPoolsCheckACL(conn, obj->def) &&
+            !virFsPoolObjIsActive(obj))
+            nactive++;
+        virFsPoolObjUnlock(obj);
+    }
+    fsDriverUnlock();
+
+    return nactive;
+}
+
+static int
+fsConnectListDefinedFsPools(virConnectPtr conn,
+                            char **const names,
+                            int nnames)
+{
+    int got = 0;
+    size_t i;
+
+    if (virConnectListDefinedFsPoolsEnsureACL(conn) < 0)
+        return -1;
+
+    fsDriverLock();
+    for (i = 0; i < driver->fspools.count && got < nnames; i++) {
+        virFsPoolObjPtr obj = driver->fspools.objs[i];
+        virFsPoolObjLock(obj);
+        if (virConnectListDefinedFsPoolsCheckACL(conn, obj->def) &&
+            !virFsPoolObjIsActive(obj)) {
+            if (VIR_STRDUP(names[got], obj->def->name) < 0) {
+                virFsPoolObjUnlock(obj);
+                goto cleanup;
+            }
+            got++;
+        }
+        virFsPoolObjUnlock(obj);
+    }
+    fsDriverUnlock();
+    return got;
+
+ cleanup:
+    fsDriverUnlock();
+    for (i = 0; i < got; i++)
+        VIR_FREE(names[i]);
+    memset(names, 0, nnames * sizeof(*names));
+    return -1;
+}
+
+static virFsPoolPtr
+fsPoolLookupByUUID(virConnectPtr conn,
+                   const unsigned char *uuid)
+{
+    virFsPoolObjPtr fspool;
+    virFsPoolPtr ret = NULL;
+
+    fsDriverLock();
+    fspool = virFsPoolObjFindByUUID(&driver->fspools, uuid);
+    fsDriverUnlock();
+
+    if (!fspool) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+        virUUIDFormat(uuid, uuidstr);
+        virReportError(VIR_ERR_NO_FS_POOL,
+                       _("no fspool with matching uuid '%s'"), uuidstr);
+        return NULL;
+    }
+
+    if (virFsPoolLookupByUUIDEnsureACL(conn, fspool->def) < 0)
+        goto cleanup;
+
+    ret = virGetFsPool(conn, fspool->def->name, fspool->def->uuid,
+                       NULL, NULL);
+
+ cleanup:
+    virFsPoolObjUnlock(fspool);
+    return ret;
+}
+
+static virFsPoolPtr
+fsPoolLookupByName(virConnectPtr conn,
+                   const char *name)
+{
+    virFsPoolObjPtr fspool;
+    virFsPoolPtr ret = NULL;
+
+    fsDriverLock();
+    fspool = virFsPoolObjFindByName(&driver->fspools, name);
+    fsDriverUnlock();
+
+    if (!fspool) {
+        virReportError(VIR_ERR_NO_FS_POOL,
+                       _("no fspool with matching name '%s'"), name);
+        return NULL;
+    }
+
+    if (virFsPoolLookupByNameEnsureACL(conn, fspool->def) < 0)
+        goto cleanup;
+
+    ret = virGetFsPool(conn, fspool->def->name, fspool->def->uuid,
+                       NULL, NULL);
+
+ cleanup:
+    virFsPoolObjUnlock(fspool);
+    return ret;
+}
+
+static virFsPoolPtr
+fsPoolLookupByItem(virFsItemPtr item)
+{
+    virFsPoolObjPtr fspool;
+    virFsPoolPtr ret = NULL;
+
+    fsDriverLock();
+    fspool = virFsPoolObjFindByName(&driver->fspools, item->fspool);
+    fsDriverUnlock();
+
+    if (!fspool) {
+        virReportError(VIR_ERR_NO_FS_POOL,
+                       _("no fspool with matching name '%s'"),
+                       item->fspool);
+        return NULL;
+    }
+
+    if (virFsPoolLookupByItemEnsureACL(item->conn, fspool->def) < 0)
+        goto cleanup;
+
+    ret = virGetFsPool(item->conn, fspool->def->name, fspool->def->uuid,
+                            NULL, NULL);
+
+ cleanup:
+    virFsPoolObjUnlock(fspool);
+    return ret;
+}
+
+
+static virFsPoolPtr
+fsPoolCreateXML(virConnectPtr conn,
+                const char *xml,
+                unsigned int flags)
+{
+    virFsPoolDefPtr def;
+    virFsPoolObjPtr fspool = NULL;
+    virFsPoolPtr ret = NULL;
+    virFsBackendPtr backend;
+    char *stateFile = NULL;
+    unsigned int build_flags = 0;
+
+    virCheckFlags(VIR_FS_POOL_CREATE_WITH_BUILD |
+                  VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE |
+                  VIR_FS_POOL_CREATE_WITH_BUILD_NO_OVERWRITE, NULL);
+
+    VIR_EXCLUSIVE_FLAGS_RET(VIR_FS_POOL_BUILD_OVERWRITE,
+                            VIR_FS_POOL_BUILD_NO_OVERWRITE, NULL);
+
+    fsDriverLock();
+    if (!(def = virFsPoolDefParseString(xml)))
+        goto cleanup;
+
+    if (virFsPoolCreateXMLEnsureACL(conn, def) < 0)
+        goto cleanup;
+
+    if (virFsPoolObjIsDuplicate(&driver->fspools, def, 1) < 0)
+        goto cleanup;
+
+    if (virFsPoolSourceFindDuplicate(conn, &driver->fspools, def) < 0)
+        goto cleanup;
+
+    if ((backend = virFsBackendForType(def->type)) == NULL)
+        goto cleanup;
+
+    if (!(fspool = virFsPoolObjAssignDef(&driver->fspools, def)))
+        goto cleanup;
+    def = NULL;
+
+    if (backend->buildFspool) {
+        if (flags & VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE)
+            build_flags |= VIR_FS_POOL_BUILD_OVERWRITE;
+        else if (flags & VIR_FS_POOL_CREATE_WITH_BUILD_NO_OVERWRITE)
+            build_flags |= VIR_FS_POOL_BUILD_NO_OVERWRITE;
+
+        if (build_flags ||
+            (flags & VIR_FS_POOL_CREATE_WITH_BUILD)) {
+            if (backend->buildFspool(conn, fspool, build_flags) < 0) {
+                virFsPoolObjRemove(&driver->fspools, fspool);
+                fspool = NULL;
+                goto cleanup;
+            }
+        }
+    }
+
+    if (backend->startFspool &&
+        backend->startFspool(conn, fspool) < 0) {
+        virFsPoolObjRemove(&driver->fspools, fspool);
+        fspool = NULL;
+        goto cleanup;
+    }
+
+    stateFile = virFileBuildPath(driver->stateDir,
+                                 fspool->def->name, ".xml");
+
+    if (!stateFile || virFsPoolSaveState(stateFile, fspool->def) < 0 ||
+        backend->refreshFspool(conn, fspool) < 0) {
+        if (stateFile)
+            unlink(stateFile);
+        if (backend->stopFspool)
+            backend->stopFspool(conn, fspool);
+        virFsPoolObjRemove(&driver->fspools, fspool);
+        fspool = NULL;
+        goto cleanup;
+    }
+    VIR_INFO("Creating fspool '%s'", fspool->def->name);
+    fspool->active = true;
+
+    ret = virGetFsPool(conn, fspool->def->name, fspool->def->uuid,
+                       NULL, NULL);
+
+ cleanup:
+    VIR_FREE(stateFile);
+    virFsPoolDefFree(def);
+    if (fspool)
+        virFsPoolObjUnlock(fspool);
+    fsDriverUnlock();
+    return ret;
+}
+
+static virFsPoolPtr
+fsPoolDefineXML(virConnectPtr conn,
+                const char *xml,
+                unsigned int flags)
+{
+    virFsPoolDefPtr def;
+    virFsPoolObjPtr fspool = NULL;
+    virFsPoolPtr ret = NULL;
+
+    virCheckFlags(0, NULL);
+
+    fsDriverLock();
+    if (!(def = virFsPoolDefParseString(xml)))
+        goto cleanup;
+
+    if (virFsPoolDefineXMLEnsureACL(conn, def) < 0)
+        goto cleanup;
+
+    if (virFsPoolObjIsDuplicate(&driver->fspools, def, 0) < 0)
+        goto cleanup;
+
+    if (virFsPoolSourceFindDuplicate(conn, &driver->fspools, def) < 0)
+        goto cleanup;
+
+    if (virFsBackendForType(def->type) == NULL)
+        goto cleanup;
+
+    if (!(fspool = virFsPoolObjAssignDef(&driver->fspools, def)))
+        goto cleanup;
+
+    if (virFsPoolObjSaveDef(driver, fspool, def) < 0) {
+        virFsPoolObjRemove(&driver->fspools, fspool);
+        def = NULL;
+        fspool = NULL;
+        goto cleanup;
+    }
+    def = NULL;
+
+    VIR_INFO("Defining fspool '%s'", fspool->def->name);
+    ret = virGetFsPool(conn, fspool->def->name, fspool->def->uuid,
+                            NULL, NULL);
+
+ cleanup:
+    virFsPoolDefFree(def);
+    if (fspool)
+        virFsPoolObjUnlock(fspool);
+    fsDriverUnlock();
+    return ret;
+}
+
+static int
+fsPoolCreate(virFsPoolPtr obj,
+             unsigned int flags)
+{
+    virFsPoolObjPtr fspool;
+    virFsBackendPtr backend;
+    int ret = -1;
+    char *stateFile = NULL;
+    unsigned int build_flags = 0;
+
+    virCheckFlags(VIR_FS_POOL_CREATE_WITH_BUILD |
+                  VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE |
+                  VIR_FS_POOL_CREATE_WITH_BUILD_NO_OVERWRITE, -1);
+
+    VIR_EXCLUSIVE_FLAGS_RET(VIR_FS_POOL_BUILD_OVERWRITE,
+                            VIR_FS_POOL_BUILD_NO_OVERWRITE, -1);
+
+    if (!(fspool = virFsPoolObjFromFsPool(obj)))
+        return -1;
+
+    if (virFsPoolCreateEnsureACL(obj->conn, fspool->def) < 0)
+        goto cleanup;
+
+    if ((backend = virFsBackendForType(fspool->def->type)) == NULL)
+        goto cleanup;
+
+    if (virFsPoolObjIsActive(fspool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("fspool '%s' is already active"),
+                       fspool->def->name);
+        goto cleanup;
+    }
+
+    if (backend->buildFspool) {
+        if (flags & VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE)
+            build_flags |= VIR_FS_POOL_BUILD_OVERWRITE;
+        else if (flags & VIR_FS_POOL_CREATE_WITH_BUILD_NO_OVERWRITE)
+            build_flags |= VIR_FS_POOL_BUILD_NO_OVERWRITE;
+
+        if (build_flags ||
+            (flags & VIR_FS_POOL_CREATE_WITH_BUILD)) {
+            if (backend->buildFspool(obj->conn, fspool, build_flags) < 0) {
+                virFsPoolObjRemove(&driver->fspools, fspool);
+                fspool = NULL;
+                goto cleanup;
+            }
+        }
+    }
+
+    VIR_INFO("Starting up fspool '%s'", fspool->def->name);
+    if (backend->startFspool &&
+        backend->startFspool(obj->conn, fspool) < 0)
+        goto cleanup;
+
+    stateFile = virFileBuildPath(driver->stateDir,
+                                 fspool->def->name, ".xml");
+
+    virFsPoolObjClearItems(fspool);
+    if (!stateFile || virFsPoolSaveState(stateFile, fspool->def) < 0 ||
+        backend->refreshFspool(obj->conn, fspool) < 0) {
+        if (stateFile)
+            unlink(stateFile);
+        goto cleanup;
+    }
+
+    fspool->active = true;
+    ret = 0;
+
+ cleanup:
+    VIR_FREE(stateFile);
+    if (fspool)
+        virFsPoolObjUnlock(fspool);
+    return ret;
+}
+
+static int
+fsPoolBuild(virFsPoolPtr obj,
+            unsigned int flags)
+{
+    virFsPoolObjPtr fspool;
+    virFsBackendPtr backend;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    if (!(fspool = virFsPoolObjFromFsPool(obj)))
+        return -1;
+
+    if (virFsPoolBuildEnsureACL(obj->conn, fspool->def) < 0)
+        goto cleanup;
+
+    if ((backend = virFsBackendForType(fspool->def->type)) == NULL)
+        goto cleanup;
+
+    if (virFsPoolObjIsActive(fspool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("fspool '%s' is already active"),
+                       fspool->def->name);
+        goto cleanup;
+    }
+
+    if (backend->buildFspool &&
+        backend->buildFspool(obj->conn, fspool, flags) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    virFsPoolObjUnlock(fspool);
+    return ret;
+}
+
+static int
+fsPoolUndefine(virFsPoolPtr obj)
+{
+    virFsPoolObjPtr fspool;
+    int ret = -1;
+
+    fsDriverLock();
+    if (!(fspool = virFsPoolObjFindByUUID(&driver->fspools, obj->uuid))) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+        virUUIDFormat(obj->uuid, uuidstr);
+        virReportError(VIR_ERR_NO_FS_POOL,
+                       _("no fspool with matching uuid '%s' (%s)"),
+                       uuidstr, obj->name);
+        goto cleanup;
+    }
+
+    if (virFsPoolUndefineEnsureACL(obj->conn, fspool->def) < 0)
+        goto cleanup;
+
+    if (virFsPoolObjIsActive(fspool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("fspool '%s' is still active"),
+                       fspool->def->name);
+        goto cleanup;
+    }
+
+    if (fspool->asyncjobs > 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("fspool '%s' has asynchronous jobs running."),
+                       fspool->def->name);
+        goto cleanup;
+    }
+
+    if (virFsPoolObjDeleteDef(fspool) < 0)
+        goto cleanup;
+
+    if (unlink(fspool->autostartLink) < 0 &&
+        errno != ENOENT &&
+        errno != ENOTDIR) {
+        char ebuf[1024];
+        VIR_ERROR(_("Failed to delete autostart link '%s': %s"),
+                  fspool->autostartLink, virStrerror(errno, ebuf, sizeof(ebuf)));
+    }
+
+    VIR_FREE(fspool->configFile);
+    VIR_FREE(fspool->autostartLink);
+
+    VIR_INFO("Undefining fspool '%s'", fspool->def->name);
+    virFsPoolObjRemove(&driver->fspools, fspool);
+    fspool = NULL;
+    ret = 0;
+
+ cleanup:
+    if (fspool)
+        virFsPoolObjUnlock(fspool);
+    fsDriverUnlock();
+    return ret;
+}
+
+static int
+fsPoolDestroy(virFsPoolPtr obj)
+{
+    virFsPoolObjPtr fspool;
+    virFsBackendPtr backend;
+    char *stateFile = NULL;
+    int ret = -1;
+
+    fsDriverLock();
+    if (!(fspool = virFsPoolObjFindByUUID(&driver->fspools, obj->uuid))) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+        virUUIDFormat(obj->uuid, uuidstr);
+        virReportError(VIR_ERR_NO_FS_POOL,
+                       _("no fspool with matching uuid '%s' (%s)"),
+                       uuidstr, obj->name);
+        goto cleanup;
+    }
+
+    if (virFsPoolDestroyEnsureACL(obj->conn, fspool->def) < 0)
+        goto cleanup;
+
+    if ((backend = virFsBackendForType(fspool->def->type)) == NULL)
+        goto cleanup;
+
+    VIR_INFO("Destroying fspool '%s'", fspool->def->name);
+
+    if (!virFsPoolObjIsActive(fspool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("fspool '%s' is not active"), fspool->def->name);
+        goto cleanup;
+    }
+
+    if (fspool->asyncjobs > 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("fspool '%s' has asynchronous jobs running."),
+                       fspool->def->name);
+        goto cleanup;
+    }
+
+    if (!(stateFile = virFileBuildPath(driver->stateDir,
+                                       fspool->def->name,
+                                       ".xml")))
+        goto cleanup;
+
+    unlink(stateFile);
+    VIR_FREE(stateFile);
+
+    if (backend->stopFspool &&
+        backend->stopFspool(obj->conn, fspool) < 0)
+        goto cleanup;
+
+    virFsPoolObjClearItems(fspool);
+
+    fspool->active = false;
+
+    if (fspool->configFile == NULL) {
+        virFsPoolObjRemove(&driver->fspools, fspool);
+        fspool = NULL;
+    } else if (fspool->newDef) {
+        virFsPoolDefFree(fspool->def);
+        fspool->def = fspool->newDef;
+        fspool->newDef = NULL;
+    }
+
+    ret = 0;
+
+ cleanup:
+    if (fspool)
+        virFsPoolObjUnlock(fspool);
+    fsDriverUnlock();
+    return ret;
+}
+
+static int
+fsPoolDelete(virFsPoolPtr obj,
+             unsigned int flags)
+{
+    virFsPoolObjPtr fspool;
+    virFsBackendPtr backend;
+    char *stateFile = NULL;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    if (!(fspool = virFsPoolObjFromFsPool(obj)))
+        return -1;
+
+    if (virFsPoolDeleteEnsureACL(obj->conn, fspool->def) < 0)
+        goto cleanup;
+
+    if ((backend = virFsBackendForType(fspool->def->type)) == NULL)
+        goto cleanup;
+
+    VIR_INFO("Deleting fspool '%s'", fspool->def->name);
+
+    if (virFsPoolObjIsActive(fspool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("fspool '%s' is still active"),
+                       fspool->def->name);
+        goto cleanup;
+    }
+
+    if (fspool->asyncjobs > 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("fspool '%s' has asynchronous jobs running."),
+                       fspool->def->name);
+        goto cleanup;
+    }
+
+    if (!(stateFile = virFileBuildPath(driver->stateDir,
+                                       fspool->def->name,
+                                       ".xml")))
+        goto cleanup;
+
+    unlink(stateFile);
+    VIR_FREE(stateFile);
+
+    if (!backend->deleteFspool) {
+        virReportError(VIR_ERR_NO_SUPPORT,
+                       "%s", _("fspool does not support fspool deletion"));
+        goto cleanup;
+    }
+    if (backend->deleteFspool(obj->conn, fspool, flags) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    virFsPoolObjUnlock(fspool);
+    return ret;
+}
+
+static int
+fsPoolRefresh(virFsPoolPtr obj,
+              unsigned int flags)
+{
+    virFsPoolObjPtr fspool;
+    virFsBackendPtr backend;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    fsDriverLock();
+    if (!(fspool = virFsPoolObjFindByUUID(&driver->fspools, obj->uuid))) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+        virUUIDFormat(obj->uuid, uuidstr);
+        virReportError(VIR_ERR_NO_FS_POOL,
+                       _("no fspool with matching uuid '%s' (%s)"),
+                       uuidstr, obj->name);
+        goto cleanup;
+    }
+
+    if (virFsPoolRefreshEnsureACL(obj->conn, fspool->def) < 0)
+        goto cleanup;
+
+    if ((backend = virFsBackendForType(fspool->def->type)) == NULL)
+        goto cleanup;
+
+    if (!virFsPoolObjIsActive(fspool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("fspool '%s' is not active"), fspool->def->name);
+        goto cleanup;
+    }
+
+    if (fspool->asyncjobs > 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("fspool '%s' has asynchronous jobs running."),
+                       fspool->def->name);
+        goto cleanup;
+    }
+
+    virFsPoolObjClearItems(fspool);
+    if (backend->refreshFspool(obj->conn, fspool) < 0) {
+        if (backend->stopFspool)
+            backend->stopFspool(obj->conn, fspool);
+
+        fspool->active = false;
+
+        if (fspool->configFile == NULL) {
+            virFsPoolObjRemove(&driver->fspools, fspool);
+            fspool = NULL;
+        }
+        goto cleanup;
+    }
+    ret = 0;
+
+ cleanup:
+    if (fspool)
+        virFsPoolObjUnlock(fspool);
+    fsDriverUnlock();
+    return ret;
+
+    return 0;
+}
+
+
+static int
+fsPoolGetInfo(virFsPoolPtr obj,
+              virFsPoolInfoPtr info)
+{
+    virFsPoolObjPtr fspool;
+    int ret = -1;
+
+    if (!(fspool = virFsPoolObjFromFsPool(obj)))
+        return -1;
+
+    if (virFsPoolGetInfoEnsureACL(obj->conn, fspool->def) < 0)
+        goto cleanup;
+
+    if (virFsBackendForType(fspool->def->type) == NULL)
+        goto cleanup;
+
+    memset(info, 0, sizeof(virFsPoolInfo));
+    if (fspool->active)
+        info->state = VIR_FS_POOL_RUNNING;
+    else
+        info->state = VIR_FS_POOL_INACTIVE;
+    info->capacity = fspool->def->capacity;
+    info->allocation = fspool->def->allocation;
+    info->available = fspool->def->available;
+    ret = 0;
+
+ cleanup:
+    virFsPoolObjUnlock(fspool);
+    return ret;
+}
+
+static char *
+fsPoolGetXMLDesc(virFsPoolPtr obj,
+                 unsigned int flags)
+{
+    virFsPoolObjPtr fspool;
+    virFsPoolDefPtr def;
+    char *ret = NULL;
+
+    virCheckFlags(VIR_FS_XML_INACTIVE, NULL);
+
+    if (!(fspool = virFsPoolObjFromFsPool(obj)))
+        return NULL;
+
+    if (virFsPoolGetXMLDescEnsureACL(obj->conn, fspool->def) < 0)
+        goto cleanup;
+
+    if ((flags & VIR_FS_XML_INACTIVE) && fspool->newDef)
+        def = fspool->newDef;
+    else
+        def = fspool->def;
+
+    ret = virFsPoolDefFormat(def);
+
+ cleanup:
+    virFsPoolObjUnlock(fspool);
+    return ret;
+}
+
+static int
+fsPoolGetAutostart(virFsPoolPtr obj, int *autostart)
+{
+    virFsPoolObjPtr fspool;
+    int ret = -1;
+
+    if (!(fspool = virFsPoolObjFromFsPool(obj)))
+        return -1;
+
+    if (virFsPoolGetAutostartEnsureACL(obj->conn, fspool->def) < 0)
+        goto cleanup;
+
+    if (!fspool->configFile) {
+        *autostart = 0;
+    } else {
+        *autostart = fspool->autostart;
+    }
+    ret = 0;
+
+ cleanup:
+    virFsPoolObjUnlock(fspool);
+    return ret;
+}
+
+static int
+fsPoolSetAutostart(virFsPoolPtr obj, int autostart)
+{
+    virFsPoolObjPtr fspool;
+    int ret = -1;
+
+    fsDriverLock();
+    fspool = virFsPoolObjFindByUUID(&driver->fspools, obj->uuid);
+
+    if (!fspool) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+        virUUIDFormat(obj->uuid, uuidstr);
+        virReportError(VIR_ERR_NO_FS_POOL,
+                       _("no fspool with matching uuid '%s' (%s)"),
+                       uuidstr, obj->name);
+        goto cleanup;
+    }
+
+    if (virFsPoolSetAutostartEnsureACL(obj->conn, fspool->def) < 0)
+        goto cleanup;
+
+    if (!fspool->configFile) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s", _("fspool has no config file"));
+        goto cleanup;
+    }
+
+    autostart = (autostart != 0);
+
+    if (fspool->autostart != autostart) {
+        if (autostart) {
+            if (virFileMakePath(driver->autostartDir) < 0) {
+                virReportSystemError(errno,
+                                     _("cannot create autostart directory %s"),
+                                     driver->autostartDir);
+                goto cleanup;
+            }
+
+            if (symlink(fspool->configFile, fspool->autostartLink) < 0) {
+                virReportSystemError(errno,
+                                     _("Failed to create symlink '%s' to '%s'"),
+                                     fspool->autostartLink, fspool->configFile);
+                goto cleanup;
+            }
+        } else {
+            if (unlink(fspool->autostartLink) < 0 &&
+                errno != ENOENT && errno != ENOTDIR) {
+                virReportSystemError(errno,
+                                     _("Failed to delete symlink '%s'"),
+                                     fspool->autostartLink);
+                goto cleanup;
+            }
+        }
+        fspool->autostart = autostart;
+    }
+    ret = 0;
+
+ cleanup:
+    if (fspool)
+        virFsPoolObjUnlock(fspool);
+    fsDriverUnlock();
+    return ret;
+}
+
+static int
+fsPoolNumOfItems(virFsPoolPtr obj)
+{
+    virFsPoolObjPtr fspool;
+    int ret = -1;
+    size_t i;
+
+    if (!(fspool = virFsPoolObjFromFsPool(obj)))
+        return -1;
+
+    if (virFsPoolNumOfItemsEnsureACL(obj->conn, fspool->def) < 0)
+        goto cleanup;
+
+    if (!virFsPoolObjIsActive(fspool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("fspool '%s' is not active"), fspool->def->name);
+        goto cleanup;
+    }
+    ret = 0;
+    for (i = 0; i < fspool->items.count; i++) {
+        if (virFsPoolNumOfItemsCheckACL(obj->conn, fspool->def,
+                                               fspool->items.objs[i]))
+            ret++;
+    }
+
+ cleanup:
+    virFsPoolObjUnlock(fspool);
+    return ret;
+}
+
+static int
+fsPoolListItems(virFsPoolPtr obj,
+                char **const names,
+                int maxnames)
+{
+    virFsPoolObjPtr fspool;
+    size_t i;
+    int n = 0;
+
+    memset(names, 0, maxnames * sizeof(*names));
+
+    if (!(fspool = virFsPoolObjFromFsPool(obj)))
+        return -1;
+
+    if (virFsPoolListItemsEnsureACL(obj->conn, fspool->def) < 0)
+        goto cleanup;
+
+    if (!virFsPoolObjIsActive(fspool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("fspool '%s' is not active"), fspool->def->name);
+        goto cleanup;
+    }
+
+    for (i = 0; i < fspool->items.count && n < maxnames; i++) {
+        if (!virFsPoolListItemsCheckACL(obj->conn, fspool->def,
+                                        fspool->items.objs[i]))
+            continue;
+        if (VIR_STRDUP(names[n++], fspool->items.objs[i]->name) < 0)
+            goto cleanup;
+    }
+
+    virFsPoolObjUnlock(fspool);
+    return n;
+
+ cleanup:
+    virFsPoolObjUnlock(fspool);
+    for (n = 0; n < maxnames; n++)
+        VIR_FREE(names[n]);
+
+    memset(names, 0, maxnames * sizeof(*names));
+    return -1;
+}
+
+static int
+fsPoolListAllItems(virFsPoolPtr fspool,
+                   virFsItemPtr **items,
+                   unsigned int flags)
+{
+    virFsPoolObjPtr obj;
+    size_t i;
+    virFsItemPtr *tmp_items = NULL;
+    virFsItemPtr item = NULL;
+    int nitems = 0;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    if (!(obj = virFsPoolObjFromFsPool(fspool)))
+        return -1;
+
+    if (virFsPoolListAllItemsEnsureACL(fspool->conn, obj->def) < 0)
+        goto cleanup;
+
+    if (!virFsPoolObjIsActive(obj)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("fspool '%s' is not active"), obj->def->name);
+        goto cleanup;
+    }
+
+     /* Just returns the items count */
+    if (!items) {
+        ret = obj->items.count;
+        goto cleanup;
+    }
+
+    if (VIR_ALLOC_N(tmp_items, obj->items.count + 1) < 0)
+        goto cleanup;
+
+    for (i = 0; i < obj->items.count; i++) {
+        if (!virFsPoolListAllItemsCheckACL(fspool->conn, obj->def,
+                                                  obj->items.objs[i]))
+            continue;
+        if (!(item = virGetFsItem(fspool->conn, obj->def->name,
+                                  obj->items.objs[i]->name,
+                                  obj->items.objs[i]->key,
+                                  NULL, NULL)))
+            goto cleanup;
+        tmp_items[nitems++] = item;
+    }
+
+    *items = tmp_items;
+    tmp_items = NULL;
+    ret = nitems;
+
+ cleanup:
+    if (tmp_items) {
+        for (i = 0; i < nitems; i++)
+            virObjectUnref(tmp_items[i]);
+        VIR_FREE(tmp_items);
+    }
+
+    virFsPoolObjUnlock(obj);
+
+    return ret;
+}
+
+static virFsItemPtr
+fsItemLookupByName(virFsPoolPtr obj, const char *name)
+{
+    virFsPoolObjPtr fspool;
+    virFsItemDefPtr item;
+    virFsItemPtr ret = NULL;
+
+    if (!(fspool = virFsPoolObjFromFsPool(obj)))
+        return NULL;
+
+    if (!virFsPoolObjIsActive(fspool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("fspool '%s' is not active"), fspool->def->name);
+        goto cleanup;
+    }
+
+    item = virFsItemDefFindByName(fspool, name);
+
+    if (!item) {
+        virReportError(VIR_ERR_NO_FS_ITEM,
+                       _("no fspool item with matching name '%s'"),
+                       name);
+        goto cleanup;
+    }
+
+    if (virFsItemLookupByNameEnsureACL(obj->conn, fspool->def, item) < 0)
+        goto cleanup;
+
+    ret = virGetFsItem(obj->conn, fspool->def->name, item->name, item->key,
+                       NULL, NULL);
+
+ cleanup:
+    virFsPoolObjUnlock(fspool);
+    return ret;
+}
+
+
+static virFsItemPtr
+fsItemLookupByKey(virConnectPtr conn, const char *key)
+{
+    size_t i;
+    virFsItemPtr ret = NULL;
+
+    fsDriverLock();
+    for (i = 0; i < driver->fspools.count && !ret; i++) {
+        virFsPoolObjLock(driver->fspools.objs[i]);
+        if (virFsPoolObjIsActive(driver->fspools.objs[i])) {
+            virFsItemDefPtr item =
+                virFsItemDefFindByKey(driver->fspools.objs[i], key);
+
+            if (item) {
+                virFsPoolDefPtr def = driver->fspools.objs[i]->def;
+                if (virFsItemLookupByKeyEnsureACL(conn, def, item) < 0) {
+                    virFsPoolObjUnlock(driver->fspools.objs[i]);
+                    goto cleanup;
+                }
+
+                ret = virGetFsItem(conn,
+                                   def->name,
+                                   item->name,
+                                   item->key,
+                                   NULL, NULL);
+            }
+        }
+        virFsPoolObjUnlock(driver->fspools.objs[i]);
+    }
+
+    if (!ret)
+        virReportError(VIR_ERR_NO_FS_ITEM,
+                       _("no fspool item with matching key %s"), key);
+
+ cleanup:
+    fsDriverUnlock();
+    return ret;
+}
+
+static virFsItemPtr
+fsItemLookupByPath(virConnectPtr conn,
+                   const char *path)
+{
+    size_t i;
+    virFsItemPtr ret = NULL;
+    char *cleanpath;
+
+    cleanpath = virFileSanitizePath(path);
+    if (!cleanpath)
+        return NULL;
+
+    fsDriverLock();
+    for (i = 0; i < driver->fspools.count && !ret; i++) {
+        virFsPoolObjPtr fspool = driver->fspools.objs[i];
+        virFsItemDefPtr item;
+
+        virFsPoolObjLock(fspool);
+
+        if (!virFsPoolObjIsActive(fspool)) {
+           virFsPoolObjUnlock(fspool);
+           continue;
+        }
+
+        item = virFsItemDefFindByPath(fspool, cleanpath);
+
+        if (item) {
+            if (virFsItemLookupByPathEnsureACL(conn, fspool->def, item) < 0) {
+                virFsPoolObjUnlock(fspool);
+                goto cleanup;
+            }
+
+            ret = virGetFsItem(conn, fspool->def->name,
+                               item->name, item->key,
+                               NULL, NULL);
+        }
+
+        virFsPoolObjUnlock(fspool);
+    }
+
+    if (!ret) {
+        if (STREQ(path, cleanpath)) {
+            virReportError(VIR_ERR_NO_FS_ITEM,
+                           _("no fspool item with matching path '%s'"), path);
+        } else {
+            virReportError(VIR_ERR_NO_FS_ITEM,
+                           _("no fspool item with matching path '%s' (%s)"),
+                           path, cleanpath);
+        }
+    }
+
+ cleanup:
+    VIR_FREE(cleanpath);
+    fsDriverUnlock();
+    return ret;
+}
+
+static virFsItemPtr
+fsItemCreateXML(virFsPoolPtr obj,
+                const char *xmldesc,
+                unsigned int flags)
+{
+    virFsPoolObjPtr fspool;
+    virFsBackendPtr backend;
+    virFsItemDefPtr itemdef = NULL;
+    virFsItemPtr ret = NULL, itemobj = NULL;
+
+    virCheckFlags(0, NULL);
+
+    if (!(fspool = virFsPoolObjFromFsPool(obj)))
+        return NULL;
+
+    if (!virFsPoolObjIsActive(fspool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("fspool '%s' is not active"), fspool->def->name);
+        goto cleanup;
+    }
+
+    if ((backend = virFsBackendForType(fspool->def->type)) == NULL)
+        goto cleanup;
+
+    itemdef = virFsItemDefParseString(fspool->def, xmldesc,
+                                      VIR_ITEM_XML_PARSE_OPT_CAPACITY);
+    if (itemdef == NULL)
+        goto cleanup;
+
+    if (!itemdef->target.capacity && !backend->buildItem) {
+        virReportError(VIR_ERR_NO_SUPPORT,
+                       "%s", _("item capacity required for this "
+                               "fspool"));
+        goto cleanup;
+    }
+
+    if (virFsItemCreateXMLEnsureACL(obj->conn, fspool->def, itemdef) < 0)
+        goto cleanup;
+
+    if (virFsItemDefFindByName(fspool, itemdef->name)) {
+        virReportError(VIR_ERR_FS_ITEM_EXIST,
+                       _("'%s'"), itemdef->name);
+        goto cleanup;
+    }
+
+    if (!backend->createItem) {
+        virReportError(VIR_ERR_NO_SUPPORT,
+                       "%s", _("fspool does not support item "
+                               "creation"));
+        goto cleanup;
+    }
+
+    if (VIR_REALLOC_N(fspool->items.objs,
+                      fspool->items.count+1) < 0)
+        goto cleanup;
+
+    /* Wipe any key the user may have suggested, as item creation
+     * will generate the canonical key.  */
+    VIR_FREE(itemdef->key);
+    if (backend->createItem(obj->conn, fspool, itemdef) < 0)
+        goto cleanup;
+
+    fspool->items.objs[fspool->items.count++] = itemdef;
+    itemobj = virGetFsItem(obj->conn, fspool->def->name, itemdef->name,
+                           itemdef->key, NULL, NULL);
+    if (!itemobj) {
+        fspool->items.count--;
+        goto cleanup;
+    }
+
+
+    if (backend->buildItem) {
+        int buildret;
+        virFsItemDefPtr builditemdef = NULL;
+
+        if (VIR_ALLOC(builditemdef) < 0) {
+            itemdef = NULL;
+            goto cleanup;
+        }
+
+        /* Make a shallow copy of the 'defined' item definition, since the
+         * original allocation value will change as the user polls 'info',
+         * but we only need the initial requested values
+         */
+        memcpy(builditemdef, itemdef, sizeof(*itemdef));
+
+        /* Drop the fspool lock during item allocation */
+        fspool->asyncjobs++;
+        itemdef->building = true;
+        virFsPoolObjUnlock(fspool);
+
+        buildret = backend->buildItem(obj->conn, fspool, builditemdef, flags);
+
+        VIR_FREE(builditemdef);
+
+        fsDriverLock();
+        virFsPoolObjLock(fspool);
+        fsDriverUnlock();
+
+        itemdef->building = false;
+        fspool->asyncjobs--;
+
+        if (buildret < 0) {
+            /* buildItem handles deleting item on failure */
+            fsItemRemoveFromFsPool(fspool, itemdef);
+            itemdef = NULL;
+            goto cleanup;
+        }
+
+    }
+
+    if (backend->refreshItem &&
+        backend->refreshItem(obj->conn, fspool, itemdef) < 0) {
+        fsItemDeleteInternal(itemobj, backend, fspool, itemdef, 0);
+        itemdef = NULL;
+        goto cleanup;
+    }
+
+    /* Update fspool metadata ignoring the disk backend since
+     * it updates the fspool values.
+     */
+
+    VIR_INFO("Creating item '%s' in fs fspool '%s'",
+             itemobj->name, fspool->def->name);
+    ret = itemobj;
+    itemobj = NULL;
+    itemdef = NULL;
+
+ cleanup:
+    virObjectUnref(itemobj);
+    virFsItemDefFree(itemdef);
+    if (fspool)
+        virFsPoolObjUnlock(fspool);
+    return ret;
+}
+
+static virFsItemPtr
+fsItemCreateXMLFrom(virFsPoolPtr obj,
+                    const char *xmldesc,
+                    virFsItemPtr vobj,
+                    unsigned int flags)
+{
+    virFsPoolObjPtr fspool, origpool = NULL;
+    virFsBackendPtr backend;
+    virFsItemDefPtr origitem = NULL, newitem = NULL, shadowitem = NULL;
+    virFsItemPtr ret = NULL, itemobj = NULL;
+    int buildret;
+
+    virCheckFlags(0, NULL);
+
+    fsDriverLock();
+    fspool = virFsPoolObjFindByUUID(&driver->fspools, obj->uuid);
+    if (fspool && STRNEQ(obj->name, vobj->fspool)) {
+        virFsPoolObjUnlock(fspool);
+        origpool = virFsPoolObjFindByName(&driver->fspools, vobj->fspool);
+        virFsPoolObjLock(fspool);
+    }
+    fsDriverUnlock();
+    if (!fspool) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+        virUUIDFormat(obj->uuid, uuidstr);
+        virReportError(VIR_ERR_NO_FS_POOL,
+                       _("no fs fspool with matching uuid '%s' (%s)"),
+                       uuidstr, obj->name);
+        goto cleanup;
+    }
+
+    if (STRNEQ(obj->name, vobj->fspool) && !origpool) {
+        virReportError(VIR_ERR_NO_FS_POOL,
+                       _("no fs fspool with matching name '%s'"),
+                       vobj->fspool);
+        goto cleanup;
+    }
+
+    if (!virFsPoolObjIsActive(fspool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("fs fspool '%s' is not active"), fspool->def->name);
+        goto cleanup;
+    }
+
+    if (origpool && !virFsPoolObjIsActive(origpool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("fs fspool '%s' is not active"),
+                       origpool->def->name);
+        goto cleanup;
+    }
+
+    if ((backend = virFsBackendForType(fspool->def->type)) == NULL)
+        goto cleanup;
+
+    origitem = virFsItemDefFindByName(origpool ?
+                                         origpool : fspool, vobj->name);
+    if (!origitem) {
+        virReportError(VIR_ERR_NO_FS_ITEM,
+                       _("no fs item with matching name '%s'"),
+                       vobj->name);
+        goto cleanup;
+    }
+
+    newitem = virFsItemDefParseString(fspool->def, xmldesc,
+                                         VIR_VOL_XML_PARSE_NO_CAPACITY);
+    if (newitem == NULL)
+        goto cleanup;
+
+    if (virFsItemCreateXMLFromEnsureACL(obj->conn, fspool->def, newitem) < 0)
+        goto cleanup;
+
+    if (virFsItemDefFindByName(fspool, newitem->name)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("fs item name '%s' already in use."),
+                       newitem->name);
+        goto cleanup;
+    }
+
+    /* Use the original item's capacity in case the new capacity
+     * is less than that, or it was omitted */
+    if (newitem->target.capacity < origitem->target.capacity)
+        newitem->target.capacity = origitem->target.capacity;
+
+    if (!backend->buildItemFrom) {
+        virReportError(VIR_ERR_NO_SUPPORT,
+                       "%s", _("fs fspool does not support"
+                               " item creation from an existing item"));
+        goto cleanup;
+    }
+
+    if (origitem->building) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("item '%s' is still being allocated."),
+                       origitem->name);
+        goto cleanup;
+    }
+
+    if (backend->refreshItem &&
+        backend->refreshItem(obj->conn, fspool, origitem) < 0)
+        goto cleanup;
+
+    if (VIR_REALLOC_N(fspool->items.objs,
+                      fspool->items.count+1) < 0)
+        goto cleanup;
+
+    /* 'Define' the new item so we get async progress reporting.
+     * Wipe any key the user may have suggested, as item creation
+     * will generate the canonical key.  */
+    VIR_FREE(newitem->key);
+    if (backend->createItem(obj->conn, fspool, newitem) < 0)
+        goto cleanup;
+
+    /* Make a shallow copy of the 'defined' item definition, since the
+     * original allocation value will change as the user polls 'info',
+     * but we only need the initial requested values
+     */
+    if (VIR_ALLOC(shadowitem) < 0)
+        goto cleanup;
+
+    memcpy(shadowitem, newitem, sizeof(*newitem));
+
+    fspool->items.objs[fspool->items.count++] = newitem;
+    itemobj = virGetFsItem(obj->conn, fspool->def->name, newitem->name,
+                              newitem->key, NULL, NULL);
+    if (!itemobj) {
+        fspool->items.count--;
+        goto cleanup;
+    }
+
+    /* Drop the fspool lock during item allocation */
+    fspool->asyncjobs++;
+    newitem->building = true;
+    origitem->in_use++;
+    virFsPoolObjUnlock(fspool);
+
+    if (origpool) {
+        origpool->asyncjobs++;
+        virFsPoolObjUnlock(origpool);
+    }
+
+    buildret = backend->buildItemFrom(obj->conn, fspool, shadowitem, origitem, flags);
+
+    fsDriverLock();
+    virFsPoolObjLock(fspool);
+    if (origpool)
+        virFsPoolObjLock(origpool);
+    fsDriverUnlock();
+
+    origitem->in_use--;
+    newitem->building = false;
+    fspool->asyncjobs--;
+
+    if (origpool) {
+        origpool->asyncjobs--;
+        virFsPoolObjUnlock(origpool);
+        origpool = NULL;
+    }
+
+    if (buildret < 0 ||
+        (backend->refreshItem &&
+         backend->refreshItem(obj->conn, fspool, newitem) < 0)) {
+        fsItemDeleteInternal(itemobj, backend, fspool, newitem, 0);
+        newitem = NULL;
+        goto cleanup;
+    }
+
+    fspool->def->allocation += newitem->target.allocation;
+    fspool->def->available -= newitem->target.allocation;
+
+    VIR_INFO("Creating item '%s' in fs fspool '%s'",
+             itemobj->name, fspool->def->name);
+    ret = itemobj;
+    itemobj = NULL;
+    newitem = NULL;
+
+ cleanup:
+    virObjectUnref(itemobj);
+    virFsItemDefFree(newitem);
+    VIR_FREE(shadowitem);
+    if (fspool)
+        virFsPoolObjUnlock(fspool);
+    if (origpool)
+        virFsPoolObjUnlock(origpool);
+    return ret;
+}
+
+
+static int
+fsItemGetInfo(virFsItemPtr obj,
+              virFsItemInfoPtr info)
+{
+    virFsPoolObjPtr fspool;
+    virFsBackendPtr backend;
+    virFsItemDefPtr item;
+    int ret = -1;
+
+    if (!(item = virFsItemDefFromItem(obj, &fspool, &backend)))
+        return -1;
+
+    if (virFsItemGetInfoEnsureACL(obj->conn, fspool->def, item) < 0)
+        goto cleanup;
+
+    if (backend->refreshItem &&
+        backend->refreshItem(obj->conn, fspool, item) < 0)
+        goto cleanup;
+
+    memset(info, 0, sizeof(*info));
+    info->type = item->type;
+    info->capacity = item->target.capacity;
+    info->allocation = item->target.allocation;
+    ret = 0;
+
+ cleanup:
+    virFsPoolObjUnlock(fspool);
+    return ret;
+}
+
+static char *
+fsItemGetXMLDesc(virFsItemPtr obj, unsigned int flags)
+{
+    virFsPoolObjPtr fspool;
+    virFsBackendPtr backend;
+    virFsItemDefPtr item;
+    char *ret = NULL;
+
+    virCheckFlags(0, NULL);
+
+    if (!(item = virFsItemDefFromItem(obj, &fspool, &backend)))
+        return NULL;
+
+    if (virFsItemGetXMLDescEnsureACL(obj->conn, fspool->def, item) < 0)
+        goto cleanup;
+
+    if (backend->refreshItem &&
+        backend->refreshItem(obj->conn, fspool, item) < 0)
+        goto cleanup;
+
+    ret = virFsItemDefFormat(fspool->def, item);
+
+ cleanup:
+    virFsPoolObjUnlock(fspool);
+
+    return ret;
+}
+
+static char *
+fsItemGetPath(virFsItemPtr obj)
+{
+    virFsPoolObjPtr fspool;
+    virFsItemDefPtr item;
+    char *ret = NULL;
+
+    if (!(item = virFsItemDefFromItem(obj, &fspool, NULL)))
+        return NULL;
+
+    if (virFsItemGetPathEnsureACL(obj->conn, fspool->def, item) < 0)
+        goto cleanup;
+
+    ignore_value(VIR_STRDUP(ret, item->target.path));
+
+ cleanup:
+    virFsPoolObjUnlock(fspool);
+    return ret;
+}
+
+
+static int fsPoolIsActive(virFsPoolPtr fspool)
+{
+    virFsPoolObjPtr obj;
+    int ret = -1;
+
+    if (!(obj = virFsPoolObjFromFsPool(fspool)))
+        return -1;
+
+    if (virFsPoolIsActiveEnsureACL(fspool->conn, obj->def) < 0)
+        goto cleanup;
+
+    ret = virFsPoolObjIsActive(obj);
+
+ cleanup:
+    virFsPoolObjUnlock(obj);
+    return ret;
+}
+
+static int fsPoolIsPersistent(virFsPoolPtr fspool)
+{
+    virFsPoolObjPtr obj;
+    int ret = -1;
+
+    if (!(obj = virFsPoolObjFromFsPool(fspool)))
+        return -1;
+
+    if (virFsPoolIsPersistentEnsureACL(fspool->conn, obj->def) < 0)
+        goto cleanup;
+
+    ret = obj->configFile ? 1 : 0;
+
+ cleanup:
+    virFsPoolObjUnlock(obj);
+    return ret;
+}
+
+
+static int
+fsItemDelete(virFsItemPtr obj,
+             unsigned int flags)
+{
+    virFsPoolObjPtr fspool;
+    virFsBackendPtr backend;
+    virFsItemDefPtr item = NULL;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    if (!(item = virFsItemDefFromItem(obj, &fspool, &backend)))
+        return -1;
+
+    if (virFsItemDeleteEnsureACL(obj->conn, fspool->def, item) < 0)
+        goto cleanup;
+
+    if (item->in_use) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("item '%s' is still in use."),
+                       item->name);
+        goto cleanup;
+    }
+
+    if (item->building) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("item '%s' is still being allocated."),
+                       item->name);
+        goto cleanup;
+    }
+
+    if (fsItemDeleteInternal(obj, backend, fspool, item, flags) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    virFsPoolObjUnlock(fspool);
+    return ret;
+}
+
+static virFsDriver fsDriver = {
+    .name = "fs",
+    .connectNumOfFsPools = fsConnectNumOfFsPools, /* 2.1.0 */
+    .connectListFsPools = fsConnectListFsPools, /* 2.1.0 */
+    .connectNumOfDefinedFsPools = fsConnectNumOfDefinedFsPools, /* 2.1.0 */
+    .connectListDefinedFsPools = fsConnectListDefinedFsPools, /* 2.1.0 */
+    .connectListAllFsPools = fsConnectListAllFsPools, /* 2.1.0 */
+    .fsPoolLookupByName = fsPoolLookupByName, /* 2.1.0 */
+    .fsPoolLookupByUUID = fsPoolLookupByUUID, /* 2.1.0 */
+    .fsPoolLookupByItem = fsPoolLookupByItem, /* 2.1.0 */
+    .fsPoolCreateXML = fsPoolCreateXML, /* 2.1.0 */
+    .fsPoolDefineXML = fsPoolDefineXML, /* 2.1.0 */
+    .fsPoolBuild = fsPoolBuild, /* 2.1.0 */
+    .fsPoolCreate = fsPoolCreate, /* 2.1.0 */
+    .fsPoolUndefine = fsPoolUndefine, /* 2.1.0 */
+    .fsPoolDestroy = fsPoolDestroy, /* 2.1.0 */
+    .fsPoolDelete = fsPoolDelete, /* 2.1.0 */
+    .fsPoolRefresh = fsPoolRefresh, /* 2.1.0 */
+    .fsPoolGetInfo = fsPoolGetInfo, /* 2.1.0 */
+    .fsPoolGetXMLDesc = fsPoolGetXMLDesc, /* 2.1.0 */
+    .fsPoolGetAutostart = fsPoolGetAutostart, /* 2.1.0 */
+    .fsPoolSetAutostart = fsPoolSetAutostart, /* 2.1.0 */
+    .fsPoolNumOfItems = fsPoolNumOfItems, /* 2.1.0 */
+    .fsPoolListItems = fsPoolListItems, /* 2.1.0 */
+    .fsPoolListAllItems = fsPoolListAllItems, /* 2.1.0 */
+    .fsItemLookupByName = fsItemLookupByName, /* 2.1.0 */
+    .fsItemLookupByKey = fsItemLookupByKey, /* 2.1.0 */
+    .fsItemLookupByPath = fsItemLookupByPath, /* 2.1.0 */
+    .fsItemCreateXML = fsItemCreateXML, /* 2.1.0 */
+    .fsItemCreateXMLFrom = fsItemCreateXMLFrom, /* 2.1.0 */
+    .fsItemDelete = fsItemDelete, /* 2.1.0 */
+    .fsItemGetInfo = fsItemGetInfo, /* 2.1.0 */
+    .fsItemGetXMLDesc = fsItemGetXMLDesc, /* 2.1.0 */
+    .fsItemGetPath = fsItemGetPath, /* 2.1.0 */
+    .fsPoolIsActive = fsPoolIsActive, /* 2.1.0 */
+    .fsPoolIsPersistent = fsPoolIsPersistent, /* 2.1.0 */
+};
+
+
+static virStateDriver stateDriver = {
+    .name = "fs",
+    .stateInitialize = fsStateInitialize,
+    .stateAutoStart = fsStateAutoStart,
+    .stateCleanup = fsStateCleanup,
+    .stateReload = fsStateReload,
+};
+
+int fsRegister(void)
+{
+    VIR_DEBUG("fsDriver = %p", &fsDriver);
+
+    if (virSetSharedFsDriver(&fsDriver) < 0)
+        return -1;
+
+    if (virRegisterStateDriver(&stateDriver) < 0)
+        return -1;
+
+    VIR_DEBUG("fsDriver = %p", &fsDriver);
+
+    return 0;
+}
diff --git a/src/fs/fs_driver.h b/src/fs/fs_driver.h
new file mode 100644
index 0000000..aaf0258
--- /dev/null
+++ b/src/fs/fs_driver.h
@@ -0,0 +1,10 @@
+#ifndef __VIR_FS_DRIVER_H__
+# define __VIR_FS_DRIVER_H__
+
+# include <sys/stat.h>
+
+# include "domain_conf.h"
+# include "fs_conf.h"
+
+int fsRegister(void);
+#endif /* __VIR_FS_DRIVER_H__ */
diff --git a/src/libvirt.c b/src/libvirt.c
index a5e0e41..19ab516 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -116,6 +116,7 @@ static int virStateDriverTabCount;
 static virNetworkDriverPtr virSharedNetworkDriver;
 static virInterfaceDriverPtr virSharedInterfaceDriver;
 static virStorageDriverPtr virSharedStorageDriver;
+static virFsDriverPtr virSharedFsDriver;
 static virNodeDeviceDriverPtr virSharedNodeDeviceDriver;
 static virSecretDriverPtr virSharedSecretDriver;
 static virNWFilterDriverPtr virSharedNWFilterDriver;
@@ -587,7 +588,30 @@ virSetSharedStorageDriver(virStorageDriverPtr driver)
     return 0;
 }
 
+/**
+ * virSetSharedFsDriver:
+ * @driver: pointer to a fs driver block
+ *
+ * Register a fs virtualization driver
+ *
+ * Returns the driver priority or -1 in case of error.
+ */
+int
+virSetSharedFsDriver(virFsDriverPtr driver)
+{
+    virCheckNonNullArgReturn(driver, -1);
 
+    if (virSharedFsDriver) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("A fs driver is already registered"));
+        return -1;
+    }
+
+    VIR_DEBUG("registering %s as fs driver", driver->name);
+
+    virSharedFsDriver = driver;
+    return 0;
+}
 /**
  * virSetSharedNodeDeviceDriver:
  * @driver: pointer to a device monitor block
@@ -707,6 +731,8 @@ virRegisterConnectDriver(virConnectDriverPtr driver,
             driver->secretDriver = virSharedSecretDriver;
         if (driver->storageDriver == NULL)
             driver->storageDriver = virSharedStorageDriver;
+        if (driver->fsDriver == NULL)
+            driver->fsDriver = virSharedFsDriver;
     }
 
     virConnectDriverTab[virConnectDriverTabCount] = driver;
@@ -1083,6 +1109,7 @@ virConnectOpenInternal(const char *name,
         ret->nwfilterDriver = virConnectDriverTab[i]->nwfilterDriver;
         ret->secretDriver = virConnectDriverTab[i]->secretDriver;
         ret->storageDriver = virConnectDriverTab[i]->storageDriver;
+        ret->fsDriver = virConnectDriverTab[i]->fsDriver;
 
         res = virConnectDriverTab[i]->hypervisorDriver->connectOpen(ret, auth, conf, flags);
         VIR_DEBUG("driver %zu %s returned %s",
@@ -1101,6 +1128,7 @@ virConnectOpenInternal(const char *name,
             ret->nwfilterDriver = NULL;
             ret->secretDriver = NULL;
             ret->storageDriver = NULL;
+            ret->fsDriver = NULL;
 
             if (res == VIR_DRV_OPEN_ERROR)
                 goto failed;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 4b87c37..b6c0e87 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1068,6 +1068,7 @@ virDomainMigratePrepareTunnel3;
 virDomainMigratePrepareTunnel3Params;
 virRegisterConnectDriver;
 virRegisterStateDriver;
+virSetSharedFsDriver;
 virSetSharedInterfaceDriver;
 virSetSharedNetworkDriver;
 virSetSharedNodeDeviceDriver;
-- 
1.8.3.1




More information about the libvir-list mailing list