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

Olga Krishtal okrishtal at virtuozzo.com
Thu Sep 15 07:32:25 UTC 2016


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>
Signed-off-by: Maxim Nestratov <mnestratov at virtuozzo.com>
---
 configure.ac             |   38 +
 daemon/Makefile.am       |    4 +
 m4/virt-driver-fspool.m4 |   52 ++
 po/POTFILES.in           |    2 +
 src/Makefile.am          |   38 +
 src/driver.h             |    1 +
 src/fs/fs_backend.h      |  107 +++
 src/fs/fs_backend_dir.c  |  355 ++++++++
 src/fs/fs_backend_dir.h  |    8 +
 src/fs/fs_driver.c       | 2058 ++++++++++++++++++++++++++++++++++++++++++++++
 src/fs/fs_driver.h       |   10 +
 src/libvirt.c            |   28 +
 src/libvirt_private.syms |    1 +
 13 files changed, 2702 insertions(+)
 create mode 100644 m4/virt-driver-fspool.m4
 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 f6076bd..5da4bf3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1074,6 +1074,11 @@ dnl
 
 LIBVIRT_DRIVER_CHECK_BHYVE
 
+dnl
+dnl Checks for FS Driver
+dnl
+
+LIBVIRT_DRIVER_CHECK_FSPOOL
 
 dnl
 dnl check for kernel headers required by src/bridge.c
@@ -1647,6 +1652,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 +2794,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([])
+LIBVIRT_DRIVER_RESULT_FS
+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/m4/virt-driver-fspool.m4 b/m4/virt-driver-fspool.m4
new file mode 100644
index 0000000..0f1a569
--- /dev/null
+++ b/m4/virt-driver-fspool.m4
@@ -0,0 +1,52 @@
+dnl The File Systems Driver
+dnl
+dnl Copyright (C) 2016 Parallels IP Holdings GmbH
+dnl
+dnl This library is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU Lesser General Public
+dnl License as published by the Free Software Foundation; either
+dnl version 2.1 of the License, or (at your option) any later version.
+dnl
+dnl This library is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+dnl Lesser General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU Lesser General Public
+dnl License along with this library.  If not, see
+dnl <http://www.gnu.org/licenses/>.
+dnl
+
+AC_DEFUN([LIBVIRT_DRIVER_CHECK_FSPOOL],[
+    AC_ARG_WITH([fs-dir],
+      [AS_HELP_STRING([--with-fs-dir],
+        [with direcktory backend for FS driver  @<:@default=yes@:>@])],
+      [],[with_fs_dir=yes])
+    m4_divert_text([DEFAULTS], [with_fs=check])
+
+    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_DEFUN([LIBVIRT_DRIVER_RESULT_FS],[
+    AC_MSG_NOTICE([       FS Driver: $with_fs_dir])
+])
diff --git a/po/POTFILES.in b/po/POTFILES.in
index f4d2f25..0fc3b79 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -59,6 +59,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 d3c6e67..0388c7d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -644,6 +644,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) \
@@ -664,6 +665,7 @@ STATEFUL_DRIVER_SOURCE_FILES = \
 	$(QEMU_DRIVER_SOURCES) \
 	$(SECRET_DRIVER_SOURCES) \
 	$(STORAGE_DRIVER_SOURCES) \
+	$(FS_DRIVER_SOURCES) \
 	$(UML_DRIVER_SOURCES) \
 	$(XEN_DRIVER_SOURCES) \
 	$(VZ_DRIVER_SOURCES) \
@@ -971,6 +973,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	\
@@ -1637,6 +1647,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 = \
@@ -1908,6 +1944,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 64f7460..07cb3fb 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..f7e0bec
--- /dev/null
+++ b/src/fs/fs_backend.h
@@ -0,0 +1,107 @@
+/*
+ * fs_backend.h: file system backend implementation
+ * Author: Olga Krishtal <okrishtal at virtuozzo.com>
+ *
+ * Copyright (C) 2016 Parallels IP Holdings GmbH
+ *
+ * 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, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+
+#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..60f18c6
--- /dev/null
+++ b/src/fs/fs_backend_dir.c
@@ -0,0 +1,355 @@
+/*
+ * fs_backend_dir.c: file system backend implementation
+ * Author: Olga Krishtal <okrishtal at virtuozzo.com>
+ *
+ * Copyright (C) 2016 Parallels IP Holdings GmbH
+ *
+ * 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, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#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_FSITEM_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_FSITEM_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_FSPOOL_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..335e008
--- /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..21fa590
--- /dev/null
+++ b/src/fs/fs_driver.c
@@ -0,0 +1,2058 @@
+/*
+ * fs_driver.c: file system driver implementation
+ * Author: Olga Krishtal <okrishtal at virtuozzo.com>
+ *
+ * Copyright (C) 2016 Parallels IP Holdings GmbH
+ *
+ * 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, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#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;
+
+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_FSPOOL,
+                       _("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_FSITEM,
+                       _("no fsitem 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_FSPOOL,
+                       _("no fspool with matching uuid '%s' (%s)"),
+                       uuidstr, fspool->name);
+    }
+    fsDriverUnlock();
+
+    return ret;
+}
+
+static int
+fsConnectListAllFSPools(virConnectPtr conn,
+                        virFSPoolPtr **fspools,
+                        unsigned int flags)
+{
+    int ret = -1;
+
+    virCheckFlags(VIR_CONNECT_LIST_FSPOOLS_FILTERS_ALL, -1);
+
+    if (virConnectListAllFSPoolsEnsureACL(conn) < 0)
+        goto cleanup;
+
+    fsDriverLock();
+    ret = virFSPoolObjListExport(conn, driver->fspools, fspools,
+                                 virConnectListAllFSPoolsCheckACL,
+                                 flags);
+    fsDriverUnlock();
+
+ cleanup:
+    return ret;
+}
+
+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_FSPOOL,
+                       _("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_FSPOOL,
+                       _("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_FSPOOL,
+                       _("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_FSPOOL_CREATE_WITH_BUILD |
+                  VIR_FSPOOL_CREATE_WITH_BUILD_OVERWRITE |
+                  VIR_FSPOOL_CREATE_WITH_BUILD_NO_OVERWRITE, NULL);
+
+    VIR_EXCLUSIVE_FLAGS_RET(VIR_FSPOOL_BUILD_OVERWRITE,
+                            VIR_FSPOOL_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_FSPOOL_CREATE_WITH_BUILD_OVERWRITE)
+            build_flags |= VIR_FSPOOL_BUILD_OVERWRITE;
+        else if (flags & VIR_FSPOOL_CREATE_WITH_BUILD_NO_OVERWRITE)
+            build_flags |= VIR_FSPOOL_BUILD_NO_OVERWRITE;
+
+        if (build_flags ||
+            (flags & VIR_FSPOOL_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_FSPOOL_CREATE_WITH_BUILD |
+                  VIR_FSPOOL_CREATE_WITH_BUILD_OVERWRITE |
+                  VIR_FSPOOL_CREATE_WITH_BUILD_NO_OVERWRITE, -1);
+
+    VIR_EXCLUSIVE_FLAGS_RET(VIR_FSPOOL_BUILD_OVERWRITE,
+                            VIR_FSPOOL_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_FSPOOL_CREATE_WITH_BUILD_OVERWRITE)
+            build_flags |= VIR_FSPOOL_BUILD_OVERWRITE;
+        else if (flags & VIR_FSPOOL_CREATE_WITH_BUILD_NO_OVERWRITE)
+            build_flags |= VIR_FSPOOL_BUILD_NO_OVERWRITE;
+
+        if (build_flags ||
+            (flags & VIR_FSPOOL_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_FSPOOL,
+                       _("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_FSPOOL,
+                       _("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_FSPOOL,
+                       _("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_FSPOOL_RUNNING;
+    else
+        info->state = VIR_FSPOOL_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_FSPOOL,
+                       _("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_FSITEM,
+                       _("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_FSITEM,
+                       _("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_FSITEM,
+                           _("no fspool item with matching path '%s'"), path);
+        } else {
+            virReportError(VIR_ERR_NO_FSITEM,
+                           _("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_FSITEM_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 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_FSPOOL,
+                       _("no fspool with matching uuid '%s' (%s)"),
+                       uuidstr, obj->name);
+        goto cleanup;
+    }
+
+    if (STRNEQ(obj->name, vobj->fspool) && !origpool) {
+        virReportError(VIR_ERR_NO_FSPOOL,
+                       _("no fspool with matching name '%s'"),
+                       vobj->fspool);
+        goto cleanup;
+    }
+
+    if (!virFSPoolObjIsActive(fspool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("fspool '%s' is not active"), fspool->def->name);
+        goto cleanup;
+    }
+
+    if (origpool && !virFSPoolObjIsActive(origpool)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("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_FSITEM,
+                       _("no fsitem 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,
+                       _("fsitem 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", _("fspool does not support"
+                               " item creation from an existing item"));
+        goto cleanup;
+    }
+
+    if (origitem->building) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("fsitem '%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 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",
+    .connectListAllFSPools = fsConnectListAllFSPools, /* 2.3.0 */
+    .fsPoolLookupByName = fsPoolLookupByName, /* 2.3.0 */
+    .fsPoolLookupByUUID = fsPoolLookupByUUID, /* 2.3.0 */
+    .fsPoolLookupByItem = fsPoolLookupByItem, /* 2.3.0 */
+    .fsPoolCreateXML = fsPoolCreateXML, /* 2.3.0 */
+    .fsPoolDefineXML = fsPoolDefineXML, /* 2.3.0 */
+    .fsPoolBuild = fsPoolBuild, /* 2.3.0 */
+    .fsPoolCreate = fsPoolCreate, /* 2.3.0 */
+    .fsPoolUndefine = fsPoolUndefine, /* 2.3.0 */
+    .fsPoolDestroy = fsPoolDestroy, /* 2.3.0 */
+    .fsPoolDelete = fsPoolDelete, /* 2.3.0 */
+    .fsPoolRefresh = fsPoolRefresh, /* 2.3.0 */
+    .fsPoolGetInfo = fsPoolGetInfo, /* 2.3.0 */
+    .fsPoolGetXMLDesc = fsPoolGetXMLDesc, /* 2.3.0 */
+    .fsPoolGetAutostart = fsPoolGetAutostart, /* 2.3.0 */
+    .fsPoolSetAutostart = fsPoolSetAutostart, /* 2.3.0 */
+    .fsPoolNumOfItems = fsPoolNumOfItems, /* 2.3.0 */
+    .fsPoolListItems = fsPoolListItems, /* 2.3.0 */
+    .fsPoolListAllItems = fsPoolListAllItems, /* 2.3.0 */
+    .fsItemLookupByName = fsItemLookupByName, /* 2.3.0 */
+    .fsItemLookupByKey = fsItemLookupByKey, /* 2.3.0 */
+    .fsItemLookupByPath = fsItemLookupByPath, /* 2.3.0 */
+    .fsItemCreateXML = fsItemCreateXML, /* 2.3.0 */
+    .fsItemCreateXMLFrom = fsItemCreateXMLFrom, /* 2.3.0 */
+    .fsItemDelete = fsItemDelete, /* 2.3.0 */
+    .fsItemGetInfo = fsItemGetInfo, /* 2.3.0 */
+    .fsItemGetXMLDesc = fsItemGetXMLDesc, /* 2.3.0 */
+    .fsItemGetPath = fsItemGetPath, /* 2.3.0 */
+    .fsPoolIsActive = fsPoolIsActive, /* 2.3.0 */
+    .fsPoolIsPersistent = fsPoolIsPersistent, /* 2.3.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 52462e3..775abdb 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;
@@ -1089,6 +1115,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",
@@ -1107,6 +1134,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 308dcc2..21ceeff 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1088,6 +1088,7 @@ virDomainMigratePrepareTunnel3;
 virDomainMigratePrepareTunnel3Params;
 virRegisterConnectDriver;
 virRegisterStateDriver;
+virSetSharedFSDriver;
 virSetSharedInterfaceDriver;
 virSetSharedNetworkDriver;
 virSetSharedNodeDeviceDriver;
-- 
1.8.3.1




More information about the libvir-list mailing list