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 <nshirokovs...@virtuozzo.com>
Signed-off-by: Maxim Nestratov <mnestra...@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 <okrish...@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 <okrish...@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 <okrish...@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

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to