diff --git a/cinder-driver/libvirt-7.0-vitastor.diff b/cinder-driver/libvirt-7.0-vitastor.diff
new file mode 100644
index 00000000..48723334
--- /dev/null
+++ b/cinder-driver/libvirt-7.0-vitastor.diff
@@ -0,0 +1,501 @@
+diff --git a/include/libvirt/libvirt-storage.h b/include/libvirt/libvirt-storage.h
+index 089e1e0..d7e7ef4 100644
+--- a/include/libvirt/libvirt-storage.h
++++ b/include/libvirt/libvirt-storage.h
+@@ -245,6 +245,7 @@ typedef enum {
+ VIR_CONNECT_LIST_STORAGE_POOLS_ZFS = 1 << 17,
+ VIR_CONNECT_LIST_STORAGE_POOLS_VSTORAGE = 1 << 18,
+ VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI_DIRECT = 1 << 19,
++ VIR_CONNECT_LIST_STORAGE_POOLS_VITASTOR = 1 << 20,
+ } virConnectListAllStoragePoolsFlags;
+
+ int virConnectListAllStoragePools(virConnectPtr conn,
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 01b7187..5b81e37 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -31392,6 +31392,7 @@ virDomainStorageSourceTranslateSourcePool(virStorageSourcePtr src,
+
+ case VIR_STORAGE_POOL_MPATH:
+ case VIR_STORAGE_POOL_RBD:
++ case VIR_STORAGE_POOL_VITASTOR:
+ case VIR_STORAGE_POOL_SHEEPDOG:
+ case VIR_STORAGE_POOL_GLUSTER:
+ case VIR_STORAGE_POOL_LAST:
+diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
+index 0c50529..fe97574 100644
+--- a/src/conf/storage_conf.c
++++ b/src/conf/storage_conf.c
+@@ -60,7 +60,7 @@ VIR_ENUM_IMPL(virStoragePool,
+ "logical", "disk", "iscsi",
+ "iscsi-direct", "scsi", "mpath",
+ "rbd", "sheepdog", "gluster",
+- "zfs", "vstorage",
++ "zfs", "vstorage", "vitastor",
+ );
+
+ VIR_ENUM_IMPL(virStoragePoolFormatFileSystem,
+@@ -249,6 +249,18 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
+ .formatToString = virStorageFileFormatTypeToString,
+ }
+ },
++ {.poolType = VIR_STORAGE_POOL_VITASTOR,
++ .poolOptions = {
++ .flags = (VIR_STORAGE_POOL_SOURCE_HOST |
++ VIR_STORAGE_POOL_SOURCE_NETWORK |
++ VIR_STORAGE_POOL_SOURCE_NAME),
++ },
++ .volOptions = {
++ .defaultFormat = VIR_STORAGE_FILE_RAW,
++ .formatFromString = virStorageVolumeFormatFromString,
++ .formatToString = virStorageFileFormatTypeToString,
++ }
++ },
+ {.poolType = VIR_STORAGE_POOL_SHEEPDOG,
+ .poolOptions = {
+ .flags = (VIR_STORAGE_POOL_SOURCE_HOST |
+@@ -551,6 +563,11 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
+ _("element 'name' is mandatory for RBD pool"));
+ goto cleanup;
+ }
++ if (pool_type == VIR_STORAGE_POOL_VITASTOR && source->name == NULL) {
++ virReportError(VIR_ERR_XML_ERROR, "%s",
++ _("element 'name' is mandatory for Vitastor pool"));
++ return -1;
++ }
+
+ if (options->formatFromString) {
+ g_autofree char *format = NULL;
+@@ -1217,6 +1234,7 @@ virStoragePoolDefFormatBuf(virBufferPtr buf,
+ /* RBD, Sheepdog, Gluster and Iscsi-direct devices are not local block devs nor
+ * files, so they don't have a target */
+ if (def->type != VIR_STORAGE_POOL_RBD &&
++ def->type != VIR_STORAGE_POOL_VITASTOR &&
+ def->type != VIR_STORAGE_POOL_SHEEPDOG &&
+ def->type != VIR_STORAGE_POOL_GLUSTER &&
+ def->type != VIR_STORAGE_POOL_ISCSI_DIRECT) {
+diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h
+index ffd406e..8868a05 100644
+--- a/src/conf/storage_conf.h
++++ b/src/conf/storage_conf.h
+@@ -110,6 +110,7 @@ typedef enum {
+ VIR_STORAGE_POOL_GLUSTER, /* Gluster device */
+ VIR_STORAGE_POOL_ZFS, /* ZFS */
+ VIR_STORAGE_POOL_VSTORAGE, /* Virtuozzo Storage */
++ VIR_STORAGE_POOL_VITASTOR, /* Vitastor */
+
+ VIR_STORAGE_POOL_LAST,
+ } virStoragePoolType;
+@@ -474,6 +475,7 @@ VIR_ENUM_DECL(virStoragePartedFs);
+ VIR_CONNECT_LIST_STORAGE_POOLS_SCSI | \
+ VIR_CONNECT_LIST_STORAGE_POOLS_MPATH | \
+ VIR_CONNECT_LIST_STORAGE_POOLS_RBD | \
++ VIR_CONNECT_LIST_STORAGE_POOLS_VITASTOR | \
+ VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG | \
+ VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER | \
+ VIR_CONNECT_LIST_STORAGE_POOLS_ZFS | \
+diff --git a/src/conf/virstorageobj.c b/src/conf/virstorageobj.c
+index 9fe8b3f..bf595b0 100644
+--- a/src/conf/virstorageobj.c
++++ b/src/conf/virstorageobj.c
+@@ -1491,6 +1491,7 @@ virStoragePoolObjSourceFindDuplicateCb(const void *payload,
+ return 1;
+ break;
+
++ case VIR_STORAGE_POOL_VITASTOR:
+ case VIR_STORAGE_POOL_RBD:
+ case VIR_STORAGE_POOL_LAST:
+ break;
+@@ -1990,6 +1991,8 @@ virStoragePoolObjMatch(virStoragePoolObjPtr obj,
+ (obj->def->type == VIR_STORAGE_POOL_MPATH)) ||
+ (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_RBD) &&
+ (obj->def->type == VIR_STORAGE_POOL_RBD)) ||
++ (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_VITASTOR) &&
++ (obj->def->type == VIR_STORAGE_POOL_VITASTOR)) ||
+ (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG) &&
+ (obj->def->type == VIR_STORAGE_POOL_SHEEPDOG)) ||
+ (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER) &&
+diff --git a/src/libvirt-storage.c b/src/libvirt-storage.c
+index 2a7cdca..f756be1 100644
+--- a/src/libvirt-storage.c
++++ b/src/libvirt-storage.c
+@@ -92,6 +92,7 @@ virStoragePoolGetConnect(virStoragePoolPtr pool)
+ * VIR_CONNECT_LIST_STORAGE_POOLS_SCSI
+ * VIR_CONNECT_LIST_STORAGE_POOLS_MPATH
+ * VIR_CONNECT_LIST_STORAGE_POOLS_RBD
++ * VIR_CONNECT_LIST_STORAGE_POOLS_VITASTOR
+ * VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG
+ * VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER
+ * VIR_CONNECT_LIST_STORAGE_POOLS_ZFS
+diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
+index f9c6da2..81cb67d 100644
+--- a/src/qemu/qemu_block.c
++++ b/src/qemu/qemu_block.c
+@@ -938,6 +938,30 @@ qemuBlockStorageSourceGetRBDProps(virStorageSourcePtr src,
+ }
+
+
++static virJSONValuePtr
++qemuBlockStorageSourceGetVitastorProps(virStorageSource *src,
++ bool onlytarget)
++{
++ qemuDomainStorageSourcePrivatePtr srcPriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(src);
++ g_autoptr(virJSONValue) servers = NULL;
++ virJSONValuePtr ret = NULL;
++
++ if (src->nhosts > 0 &&
++ !(servers = qemuBlockStorageSourceBuildHostsJSONInetSocketAddress(src)))
++ return NULL;
++
++ if (virJSONValueObjectCreate(&ret,
++ "A:server", &servers,
++ "s:etcd_prefix", src->query,
++ "S:config_path", src->configFile,
++ "s:image", src->path,
++ NULL) < 0)
++ return NULL;
++
++ return ret;
++}
++
++
+ static virJSONValuePtr
+ qemuBlockStorageSourceGetSheepdogProps(virStorageSourcePtr src)
+ {
+@@ -1224,6 +1248,12 @@ qemuBlockStorageSourceGetBackendProps(virStorageSourcePtr src,
+ return NULL;
+ break;
+
++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
++ driver = "vitastor";
++ if (!(fileprops = qemuBlockStorageSourceGetVitastorProps(src, onlytarget)))
++ return NULL;
++ break;
++
+ case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
+ driver = "sheepdog";
+ if (!(fileprops = qemuBlockStorageSourceGetSheepdogProps(src)))
+@@ -2183,6 +2213,7 @@ qemuBlockGetBackingStoreString(virStorageSourcePtr src,
+
+ case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
+ case VIR_STORAGE_NET_PROTOCOL_RBD:
++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
+ case VIR_STORAGE_NET_PROTOCOL_VXHS:
+ case VIR_STORAGE_NET_PROTOCOL_NFS:
+ case VIR_STORAGE_NET_PROTOCOL_SSH:
+@@ -2560,6 +2591,12 @@ qemuBlockStorageSourceCreateGetStorageProps(virStorageSourcePtr src,
+ return -1;
+ break;
+
++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
++ driver = "vitastor";
++ if (!(location = qemuBlockStorageSourceGetVitastorProps(src, false)))
++ return -1;
++ break;
++
+ case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
+ driver = "sheepdog";
+ if (!(location = qemuBlockStorageSourceGetSheepdogProps(src)))
+diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
+index 6f970a3..10b39ca 100644
+--- a/src/qemu/qemu_command.c
++++ b/src/qemu/qemu_command.c
+@@ -1034,6 +1034,43 @@ qemuBuildNetworkDriveStr(virStorageSourcePtr src,
+ ret = virBufferContentAndReset(&buf);
+ break;
+
++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
++ if (strchr(src->path, ':')) {
++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
++ _("':' not allowed in Vitastor source volume name '%s'"),
++ src->path);
++ return NULL;
++ }
++
++ virBufferStrcat(&buf, "vitastor:image=", src->path, NULL);
++
++ if (src->nhosts > 0) {
++ virBufferAddLit(&buf, ":etcd_host=");
++ for (i = 0; i < src->nhosts; i++) {
++ if (i)
++ virBufferAddLit(&buf, ",");
++
++ /* assume host containing : is ipv6 */
++ if (strchr(src->hosts[i].name, ':'))
++ virBufferEscape(&buf, '\\', ":", "[%s]",
++ src->hosts[i].name);
++ else
++ virBufferAsprintf(&buf, "%s", src->hosts[i].name);
++
++ if (src->hosts[i].port)
++ virBufferAsprintf(&buf, "\\:%u", src->hosts[i].port);
++ }
++ }
++
++ if (src->configFile)
++ virBufferEscape(&buf, '\\', ":", ":config_path=%s", src->configFile);
++
++ if (src->query)
++ virBufferEscape(&buf, '\\', ":", ":etcd_prefix=%s", src->query);
++
++ ret = virBufferContentAndReset(&buf);
++ break;
++
+ case VIR_STORAGE_NET_PROTOCOL_VXHS:
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("VxHS protocol does not support URI syntax"));
+diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
+index 0765dc7..c69b1f1 100644
+--- a/src/qemu/qemu_domain.c
++++ b/src/qemu/qemu_domain.c
+@@ -9704,6 +9704,7 @@ qemuDomainPrepareStorageSourceTLS(virStorageSourcePtr src,
+ break;
+
+ case VIR_STORAGE_NET_PROTOCOL_RBD:
++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
+ case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
+ case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
+ case VIR_STORAGE_NET_PROTOCOL_ISCSI:
+diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c
+index ee333c3..674aa58 100644
+--- a/src/qemu/qemu_snapshot.c
++++ b/src/qemu/qemu_snapshot.c
+@@ -403,6 +403,7 @@ qemuSnapshotPrepareDiskExternalInactive(virDomainSnapshotDiskDefPtr snapdisk,
+ case VIR_STORAGE_NET_PROTOCOL_NONE:
+ case VIR_STORAGE_NET_PROTOCOL_NBD:
+ case VIR_STORAGE_NET_PROTOCOL_RBD:
++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
+ case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
+ case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
+ case VIR_STORAGE_NET_PROTOCOL_ISCSI:
+@@ -493,6 +494,7 @@ qemuSnapshotPrepareDiskExternalActive(virDomainObjPtr vm,
+ case VIR_STORAGE_NET_PROTOCOL_NONE:
+ case VIR_STORAGE_NET_PROTOCOL_NBD:
+ case VIR_STORAGE_NET_PROTOCOL_RBD:
++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
+ case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
+ case VIR_STORAGE_NET_PROTOCOL_ISCSI:
+ case VIR_STORAGE_NET_PROTOCOL_HTTP:
+@@ -623,6 +625,7 @@ qemuSnapshotPrepareDiskInternal(virDomainDiskDefPtr disk,
+ case VIR_STORAGE_NET_PROTOCOL_NONE:
+ case VIR_STORAGE_NET_PROTOCOL_NBD:
+ case VIR_STORAGE_NET_PROTOCOL_RBD:
++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
+ case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
+ case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
+ case VIR_STORAGE_NET_PROTOCOL_ISCSI:
+diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c
+index 0d3c2af..36e3afc 100644
+--- a/src/util/virstoragefile.c
++++ b/src/util/virstoragefile.c
+@@ -91,6 +91,7 @@ VIR_ENUM_IMPL(virStorageNetProtocol,
+ "ssh",
+ "vxhs",
+ "nfs",
++ "vitastor",
+ );
+
+ VIR_ENUM_IMPL(virStorageNetHostTransport,
+@@ -2880,6 +2881,75 @@ virStorageSourceParseRBDColonString(const char *rbdstr,
+ }
+
+
++static int
++virStorageSourceParseVitastorColonString(const char *colonstr,
++ virStorageSourcePtr src)
++{
++ char *p, *e, *next;
++ g_autofree char *options = NULL;
++
++ /* optionally skip the "vitastor:" prefix if provided */
++ if (STRPREFIX(colonstr, "vitastor:"))
++ colonstr += strlen("vitastor:");
++
++ options = g_strdup(colonstr);
++
++ p = options;
++ while (*p) {
++ /* find : delimiter or end of string */
++ for (e = p; *e && *e != ':'; ++e) {
++ if (*e == '\\') {
++ e++;
++ if (*e == '\0')
++ break;
++ }
++ }
++ if (*e == '\0') {
++ next = e; /* last kv pair */
++ } else {
++ next = e + 1;
++ *e = '\0';
++ }
++
++ if (STRPREFIX(p, "image=")) {
++ src->path = g_strdup(p + strlen("image="));
++ } else if (STRPREFIX(p, "etcd_prefix=")) {
++ src->query = g_strdup(p + strlen("etcd_prefix="));
++ } else if (STRPREFIX(p, "config_file=")) {
++ src->configFile = g_strdup(p + strlen("config_file="));
++ } else if (STRPREFIX(p, "etcd_host=")) {
++ char *h, *sep;
++
++ h = p + strlen("etcd_host=");
++ while (h < e) {
++ for (sep = h; sep < e; ++sep) {
++ if (*sep == '\\' && (sep[1] == ',' ||
++ sep[1] == ';' ||
++ sep[1] == ' ')) {
++ *sep = '\0';
++ sep += 2;
++ break;
++ }
++ }
++
++ if (virStorageSourceRBDAddHost(src, h) < 0)
++ return -1;
++
++ h = sep;
++ }
++ }
++
++ p = next;
++ }
++
++ if (!src->path) {
++ return -1;
++ }
++
++ return 0;
++}
++
++
+ static int
+ virStorageSourceParseNBDColonString(const char *nbdstr,
+ virStorageSourcePtr src)
+@@ -2992,6 +3062,11 @@ virStorageSourceParseBackingColon(virStorageSourcePtr src,
+ return -1;
+ break;
+
++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
++ if (virStorageSourceParseVitastorColonString(path, src) < 0)
++ return -1;
++ break;
++
+ case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
+ case VIR_STORAGE_NET_PROTOCOL_LAST:
+ case VIR_STORAGE_NET_PROTOCOL_NONE:
+@@ -3581,6 +3656,54 @@ virStorageSourceParseBackingJSONRBD(virStorageSourcePtr src,
+ return 0;
+ }
+
++static int
++virStorageSourceParseBackingJSONVitastor(virStorageSourcePtr src,
++ virJSONValuePtr json,
++ const char *jsonstr G_GNUC_UNUSED,
++ int opaque G_GNUC_UNUSED)
++{
++ const char *filename;
++ const char *image = virJSONValueObjectGetString(json, "image");
++ const char *conf = virJSONValueObjectGetString(json, "config_path");
++ const char *etcd_prefix = virJSONValueObjectGetString(json, "etcd_prefix");
++ virJSONValuePtr servers = virJSONValueObjectGetArray(json, "server");
++ size_t nservers;
++ size_t i;
++
++ src->type = VIR_STORAGE_TYPE_NETWORK;
++ src->protocol = VIR_STORAGE_NET_PROTOCOL_VITASTOR;
++
++ /* legacy syntax passed via 'filename' option */
++ if ((filename = virJSONValueObjectGetString(json, "filename")))
++ return virStorageSourceParseVitastorColonString(filename, src);
++
++ if (!image) {
++ virReportError(VIR_ERR_INVALID_ARG, "%s",
++ _("missing image name in Vitastor backing volume "
++ "JSON specification"));
++ return -1;
++ }
++
++ src->path = g_strdup(image);
++ src->configFile = g_strdup(conf);
++ src->query = g_strdup(etcd_prefix);
++
++ if (servers) {
++ nservers = virJSONValueArraySize(servers);
++
++ src->hosts = g_new0(virStorageNetHostDef, nservers);
++ src->nhosts = nservers;
++
++ for (i = 0; i < nservers; i++) {
++ if (virStorageSourceParseBackingJSONInetSocketAddress(src->hosts + i,
++ virJSONValueArrayGet(servers, i)) < 0)
++ return -1;
++ }
++ }
++
++ return 0;
++}
++
+ static int
+ virStorageSourceParseBackingJSONRaw(virStorageSourcePtr src,
+ virJSONValuePtr json,
+@@ -3759,6 +3882,7 @@ static const struct virStorageSourceJSONDriverParser jsonParsers[] = {
+ {"sheepdog", false, virStorageSourceParseBackingJSONSheepdog, 0},
+ {"ssh", false, virStorageSourceParseBackingJSONSSH, 0},
+ {"rbd", false, virStorageSourceParseBackingJSONRBD, 0},
++ {"vitastor", false, virStorageSourceParseBackingJSONVitastor, 0},
+ {"raw", true, virStorageSourceParseBackingJSONRaw, 0},
+ {"nfs", false, virStorageSourceParseBackingJSONNFS, 0},
+ {"vxhs", false, virStorageSourceParseBackingJSONVxHS, 0},
+@@ -4503,6 +4627,7 @@ virStorageSourceNetworkDefaultPort(virStorageNetProtocol protocol)
+ case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
+ return 24007;
+
++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR:
+ case VIR_STORAGE_NET_PROTOCOL_RBD:
+ /* we don't provide a default for RBD */
+ return 0;
+diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h
+index 5689c39..3eb4e3c 100644
+--- a/src/util/virstoragefile.h
++++ b/src/util/virstoragefile.h
+@@ -136,6 +136,7 @@ typedef enum {
+ VIR_STORAGE_NET_PROTOCOL_SSH,
+ VIR_STORAGE_NET_PROTOCOL_VXHS,
+ VIR_STORAGE_NET_PROTOCOL_NFS,
++ VIR_STORAGE_NET_PROTOCOL_VITASTOR,
+
+ VIR_STORAGE_NET_PROTOCOL_LAST
+ } virStorageNetProtocol;
+diff --git a/tests/storagepoolcapsschemadata/poolcaps-fs.xml b/tests/storagepoolcapsschemadata/poolcaps-fs.xml
+index eee75af..8bd0a57 100644
+--- a/tests/storagepoolcapsschemadata/poolcaps-fs.xml
++++ b/tests/storagepoolcapsschemadata/poolcaps-fs.xml
+@@ -204,4 +204,11 @@
+
+
+
++
++
++
++
++
++
++
+
+diff --git a/tests/storagepoolcapsschemadata/poolcaps-full.xml b/tests/storagepoolcapsschemadata/poolcaps-full.xml
+index 805950a..852df0d 100644
+--- a/tests/storagepoolcapsschemadata/poolcaps-full.xml
++++ b/tests/storagepoolcapsschemadata/poolcaps-full.xml
+@@ -204,4 +204,11 @@
+
+
+
++
++
++
++
++
++
++
+