[libvirt] [PATCH RFC 0/6] Add support for snapshots on gluster.

This series has to be applied on top of the refactoring series sent earlier today. First 3 patches are additional fixes that should be good to be commited. The rest is work in progress state to gather possible comments. Peter Krempa (6): qemu: snapshot: Touch up error message qemu: snapshot: Add functions similar to disk source pool translation qemu: snapshots: Declare supported and unsupported snapshot configs RFC: snapshot: Add support for specifying snapshot disk backing type RFC: conf: snapshot: Parse more snapshot information RFC: qemu: snapshot: Add support for external active snapshots on gluster src/conf/snapshot_conf.c | 21 ++- src/conf/snapshot_conf.h | 15 +- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_command.h | 9 + src/qemu/qemu_conf.c | 23 +++ src/qemu/qemu_conf.h | 6 + src/qemu/qemu_driver.c | 426 ++++++++++++++++++++++++++++++++++++++++------- 7 files changed, 434 insertions(+), 68 deletions(-) -- 1.8.4.3

--- src/qemu/qemu_driver.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d2dbaf5..96bc87e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -11858,8 +11858,8 @@ qemuDomainSnapshotPrepare(virDomainObjPtr vm, virDomainSnapshotDefPtr def, * offline snapshots */ if (found_internal && external) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("mixing internal and external snapshots is not " - "supported yet")); + _("mixing internal and external targets for a snapshot " + "is not yet supported")); goto cleanup; } -- 1.8.4.3

To avoid future pain, add placeholder functions to get the actual snapshot disk type. --- src/qemu/qemu_conf.c | 23 +++++++++++++++++++++++ src/qemu/qemu_conf.h | 6 ++++++ 2 files changed, 29 insertions(+) diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 1192d23..4ccca1f 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -1451,3 +1451,26 @@ cleanup: virStoragePoolDefFree(pooldef); return ret; } + + +int +qemuSnapshotDiskGetActualType(virDomainSnapshotDiskDefPtr def) +{ + if (def->type == -1) + return VIR_DOMAIN_DISK_TYPE_FILE; + + return def->type; +} + + +int +qemuTranslateSnapshotDiskSourcePool(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainSnapshotDiskDefPtr def) +{ + if (def->type != VIR_DOMAIN_DISK_TYPE_VOLUME) + return 0; + + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Snapshots are not yet supported with 'pool' volumes")); + return -1; +} diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index b9786b1..0cb7901 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -29,6 +29,7 @@ # include "capabilities.h" # include "network_conf.h" # include "domain_conf.h" +# include "snapshot_conf.h" # include "domain_event.h" # include "virthread.h" # include "security/security_manager.h" @@ -309,4 +310,9 @@ int qemuDiskGetActualType(virDomainDiskDefPtr def); int qemuTranslateDiskSourcePool(virConnectPtr conn, virDomainDiskDefPtr def); +int qemuSnapshotDiskGetActualType(virDomainSnapshotDiskDefPtr def); + +int qemuTranslateSnapshotDiskSourcePool(virConnectPtr conn, + virDomainSnapshotDiskDefPtr def); + #endif /* __QEMUD_CONF_H */ -- 1.8.4.3

Currently the snapshot code did not check if it actually supports snapshots on various disk backends for domains. To avoid future problems add checkers that whitelist the supported configurations. --- src/qemu/qemu_driver.c | 264 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 234 insertions(+), 30 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 96bc87e..b9c270b 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -11738,13 +11738,226 @@ endjob: } static int -qemuDomainSnapshotPrepare(virDomainObjPtr vm, virDomainSnapshotDefPtr def, +qemuDomainSnapshotPrepareDiskExternalBacking(virDomainDiskDefPtr disk) +{ + int actualType = qemuDiskGetActualType(disk); + + switch ((enum virDomainDiskType) actualType) { + case VIR_DOMAIN_DISK_TYPE_BLOCK: + case VIR_DOMAIN_DISK_TYPE_FILE: + return 0; + + case VIR_DOMAIN_DISK_TYPE_NETWORK: + switch ((enum virDomainDiskProtocol) disk->protocol) { + case VIR_DOMAIN_DISK_PROTOCOL_NBD: + case VIR_DOMAIN_DISK_PROTOCOL_RBD: + case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG: + case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER: + case VIR_DOMAIN_DISK_PROTOCOL_ISCSI: + case VIR_DOMAIN_DISK_PROTOCOL_HTTP: + case VIR_DOMAIN_DISK_PROTOCOL_HTTPS: + case VIR_DOMAIN_DISK_PROTOCOL_FTP: + case VIR_DOMAIN_DISK_PROTOCOL_FTPS: + case VIR_DOMAIN_DISK_PROTOCOL_TFTP: + case VIR_DOMAIN_DISK_PROTOCOL_LAST: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("external inactive snapshots are not supported on " + "'network' disks using '%s' protocol"), + virDomainDiskProtocolTypeToString(disk->protocol)); + return -1; + } + break; + + case VIR_DOMAIN_DISK_TYPE_DIR: + case VIR_DOMAIN_DISK_TYPE_VOLUME: + case VIR_DOMAIN_DISK_TYPE_LAST: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("external inactive snapshots are not supported on " + "'%s' disks"), virDomainDiskTypeToString(actualType)); + return -1; + } + + return 0; +} + + +static int +qemuDomainSnapshotPrepareDiskExternalOverlayActive(virDomainSnapshotDiskDefPtr disk) +{ + int actualType = qemuSnapshotDiskGetActualType(disk); + + switch ((enum virDomainDiskType) actualType) { + case VIR_DOMAIN_DISK_TYPE_BLOCK: + case VIR_DOMAIN_DISK_TYPE_FILE: + return 0; + + case VIR_DOMAIN_DISK_TYPE_NETWORK: + case VIR_DOMAIN_DISK_TYPE_DIR: + case VIR_DOMAIN_DISK_TYPE_VOLUME: + case VIR_DOMAIN_DISK_TYPE_LAST: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("external active snapshots are not supported on " + "'%s' disks"), virDomainDiskTypeToString(actualType)); + return -1; + } + + return 0; +} + + +static int +qemuDomainSnapshotPrepareDiskExternalOverlayInactive(virDomainSnapshotDiskDefPtr disk) +{ + int actualType = qemuSnapshotDiskGetActualType(disk); + + switch ((enum virDomainDiskType) actualType) { + case VIR_DOMAIN_DISK_TYPE_BLOCK: + case VIR_DOMAIN_DISK_TYPE_FILE: + return 0; + + case VIR_DOMAIN_DISK_TYPE_NETWORK: + case VIR_DOMAIN_DISK_TYPE_DIR: + case VIR_DOMAIN_DISK_TYPE_VOLUME: + case VIR_DOMAIN_DISK_TYPE_LAST: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("external inactive snapshots are not supported on " + "'%s' disks"), virDomainDiskTypeToString(actualType)); + return -1; + } + + return 0; +} + + + +static int +qemuDomainSnapshotPrepareDiskExternal(virConnectPtr conn, + virDomainDiskDefPtr disk, + virDomainSnapshotDiskDefPtr snapdisk, + bool active, + bool reuse) +{ + int actualType; + struct stat st; + + if (qemuTranslateSnapshotDiskSourcePool(conn, snapdisk) < 0) + return -1; + + if (!active) { + if (qemuTranslateDiskSourcePool(conn, disk) < 0) + return -1; + + if (qemuDomainSnapshotPrepareDiskExternalBacking(disk) < 0) + return -1; + + if (qemuDomainSnapshotPrepareDiskExternalOverlayInactive(snapdisk) < 0) + return -1; + } else { + if (qemuDomainSnapshotPrepareDiskExternalOverlayActive(snapdisk) < 0) + return -1; + } + + actualType = qemuSnapshotDiskGetActualType(snapdisk); + + switch ((enum virDomainDiskType) actualType) { + case VIR_DOMAIN_DISK_TYPE_BLOCK: + case VIR_DOMAIN_DISK_TYPE_FILE: + if (stat(snapdisk->file, &st) < 0) { + if (errno != ENOENT) { + virReportSystemError(errno, + _("unable to stat for disk %s: %s"), + snapdisk->name, snapdisk->file); + return -1; + } else if (reuse) { + virReportSystemError(errno, + _("missing existing file for disk %s: %s"), + snapdisk->name, snapdisk->file); + return -1; + } + } else if (!S_ISBLK(st.st_mode) && st.st_size && !reuse) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("external snapshot file for disk %s already " + "exists and is not a block device: %s"), + snapdisk->name, snapdisk->file); + return -1; + } + break; + + case VIR_DOMAIN_DISK_TYPE_NETWORK: + case VIR_DOMAIN_DISK_TYPE_DIR: + case VIR_DOMAIN_DISK_TYPE_VOLUME: + case VIR_DOMAIN_DISK_TYPE_LAST: + break; + } + + return 0; +} + + +static int +qemuDomainSnapshotPrepareDiskInternal(virConnectPtr conn, + virDomainDiskDefPtr disk, + bool active) +{ + int actualType; + + /* active disks are handeled by qemu itself so no need to worry about those */ + if (active) + return 0; + + if (qemuTranslateDiskSourcePool(conn, disk) < 0) + return -1; + + actualType = qemuDiskGetActualType(disk); + + switch ((enum virDomainDiskType) actualType) { + case VIR_DOMAIN_DISK_TYPE_BLOCK: + case VIR_DOMAIN_DISK_TYPE_FILE: + return 0; + + case VIR_DOMAIN_DISK_TYPE_NETWORK: + switch ((enum virDomainDiskProtocol) disk->protocol) { + case VIR_DOMAIN_DISK_PROTOCOL_NBD: + case VIR_DOMAIN_DISK_PROTOCOL_RBD: + case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG: + case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER: + case VIR_DOMAIN_DISK_PROTOCOL_ISCSI: + case VIR_DOMAIN_DISK_PROTOCOL_HTTP: + case VIR_DOMAIN_DISK_PROTOCOL_HTTPS: + case VIR_DOMAIN_DISK_PROTOCOL_FTP: + case VIR_DOMAIN_DISK_PROTOCOL_FTPS: + case VIR_DOMAIN_DISK_PROTOCOL_TFTP: + case VIR_DOMAIN_DISK_PROTOCOL_LAST: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("internal inactive snapshots are not supported on " + "'network' disks using '%s' protocol"), + virDomainDiskProtocolTypeToString(disk->protocol)); + return -1; + } + break; + + case VIR_DOMAIN_DISK_TYPE_DIR: + case VIR_DOMAIN_DISK_TYPE_VOLUME: + case VIR_DOMAIN_DISK_TYPE_LAST: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("internal inactive snapshots are not supported on " + "'%s' disks"), virDomainDiskTypeToString(actualType)); + return -1; + } + + return 0; +} + + +static int +qemuDomainSnapshotPrepare(virConnectPtr conn, + virDomainObjPtr vm, + virDomainSnapshotDefPtr def, unsigned int *flags) { int ret = -1; size_t i; bool active = virDomainObjIsActive(vm); - struct stat st; bool reuse = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0; bool atomic = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC) != 0; bool found_internal = false; @@ -11766,8 +11979,19 @@ qemuDomainSnapshotPrepare(virDomainObjPtr vm, virDomainSnapshotDefPtr def, case VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL: found_internal = true; - if (def->state != VIR_DOMAIN_DISK_SNAPSHOT && - dom_disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK && + if (def->state == VIR_DOMAIN_DISK_SNAPSHOT && active) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("active qemu domains require external disk " + "snapshots; disk %s requested internal"), + disk->name); + goto cleanup; + } + + if (qemuDomainSnapshotPrepareDiskInternal(conn, dom_disk, + active) < 0) + goto cleanup; + + if (dom_disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK && (dom_disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG || dom_disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD)) { break; @@ -11782,13 +12006,6 @@ qemuDomainSnapshotPrepare(virDomainObjPtr vm, virDomainSnapshotDefPtr def, vm->def->disks[i]->format)); goto cleanup; } - if (def->state == VIR_DOMAIN_DISK_SNAPSHOT && active) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("active qemu domains require external disk " - "snapshots; disk %s requested internal"), - disk->name); - goto cleanup; - } break; case VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL: @@ -11803,25 +12020,11 @@ qemuDomainSnapshotPrepare(virDomainObjPtr vm, virDomainSnapshotDefPtr def, virStorageFileFormatTypeToString(disk->format)); goto cleanup; } - if (stat(disk->file, &st) < 0) { - if (errno != ENOENT) { - virReportSystemError(errno, - _("unable to stat for disk %s: %s"), - disk->name, disk->file); - goto cleanup; - } else if (reuse) { - virReportSystemError(errno, - _("missing existing file for disk %s: %s"), - disk->name, disk->file); - goto cleanup; - } - } else if (!S_ISBLK(st.st_mode) && st.st_size && !reuse) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("external snapshot file for disk %s already " - "exists and is not a block device: %s"), - disk->name, disk->file); + + if (qemuDomainSnapshotPrepareDiskExternal(conn, dom_disk, disk, + active, reuse) < 0) goto cleanup; - } + external++; break; @@ -12326,6 +12529,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain, const char *xmlDesc, unsigned int flags) { + virConnectPtr conn = domain->conn; virQEMUDriverPtr driver = domain->conn->privateData; virDomainObjPtr vm = NULL; char *xml = NULL; @@ -12464,7 +12668,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain, } if (virDomainSnapshotAlignDisks(def, align_location, align_match) < 0 || - qemuDomainSnapshotPrepare(vm, def, &flags) < 0) + qemuDomainSnapshotPrepare(conn, vm, def, &flags) < 0) goto cleanup; } -- 1.8.4.3

Add support for specifying various types when doing snapshots. This will later allow to do snapshots on network backed volumes. RFC: This patch is lacking tests and domain schema touch up. --- src/conf/snapshot_conf.c | 9 ++++++++ src/qemu/qemu_driver.c | 56 +++++++++++++++++++++++++++++++----------------- 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index 5958f13..f6f170e 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -108,6 +108,7 @@ virDomainSnapshotDiskDefParseXML(xmlNodePtr node, { int ret = -1; char *snapshot = NULL; + char *type = NULL; xmlNodePtr cur; def->name = virXMLPropString(node, "name"); @@ -129,6 +130,13 @@ virDomainSnapshotDiskDefParseXML(xmlNodePtr node, } def->type = -1; + if ((type = virXMLPropString(node, "type"))) { + if ((def->type = virDomainDiskTypeFromString(type)) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("unknown disk snapshot type '%s'"), type); + goto cleanup; + } + } for (cur = node->children; cur; cur = cur->next) { if (cur->type != XML_ELEMENT_NODE) @@ -174,6 +182,7 @@ virDomainSnapshotDiskDefParseXML(xmlNodePtr node, ret = 0; cleanup: VIR_FREE(snapshot); + VIR_FREE(type); if (ret < 0) virDomainSnapshotDiskDefClear(def); return ret; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index b9c270b..e6d4f47 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12115,33 +12115,48 @@ qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr driver, } if (virAsprintf(&device, "drive-%s", disk->info.alias) < 0 || - VIR_STRDUP(source, snap->file) < 0 || (persistDisk && VIR_STRDUP(persistSource, source) < 0)) goto cleanup; - /* create the stub file and set selinux labels; manipulate disk in - * place, in a way that can be reverted on failure. */ - if (!reuse) { - fd = qemuOpenFile(driver, vm, source, O_WRONLY | O_TRUNC | O_CREAT, - &need_unlink, NULL); - if (fd < 0) - goto cleanup; - VIR_FORCE_CLOSE(fd); - } - /* XXX Here, we know we are about to alter disk->backingChain if - * successful, so we nuke the existing chain so that future - * commands will recompute it. Better would be storing the chain - * ourselves rather than reprobing, but this requires modifying - * domain_conf and our XML to fully track the chain across - * libvirtd restarts. */ + * successful, so we nuke the existing chain so that future commands will + * recompute it. Better would be storing the chain ourselves rather than + * reprobing, but this requires modifying domain_conf and our XML to fully + * track the chain across libvirtd restarts. */ virStorageFileFreeMetadata(disk->backingChain); disk->backingChain = NULL; - if (qemuDomainPrepareDiskChainElement(driver, vm, disk, source, - VIR_DISK_CHAIN_READ_WRITE) < 0) { - qemuDomainPrepareDiskChainElement(driver, vm, disk, source, - VIR_DISK_CHAIN_NO_ACCESS); + switch (snap->type) { + case VIR_DOMAIN_DISK_TYPE_BLOCK: + reuse = true; + /* fallthrough */ + case -1: /* type was not provided in snapshot conf */ + case VIR_DOMAIN_DISK_TYPE_FILE: + if (VIR_STRDUP(source, snap->file) < 0) + goto cleanup; + + /* create the stub file and set selinux labels; manipulate disk in + * place, in a way that can be reverted on failure. */ + if (!reuse) { + fd = qemuOpenFile(driver, vm, source, O_WRONLY | O_TRUNC | O_CREAT, + &need_unlink, NULL); + if (fd < 0) + goto cleanup; + VIR_FORCE_CLOSE(fd); + } + + if (qemuDomainPrepareDiskChainElement(driver, vm, disk, source, + VIR_DISK_CHAIN_READ_WRITE) < 0) { + qemuDomainPrepareDiskChainElement(driver, vm, disk, source, + VIR_DISK_CHAIN_NO_ACCESS); + goto cleanup; + } + break; + + default: + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("snapshots are not supported on '%s' volumes"), + virDomainDiskTypeToString(snap->type)); goto cleanup; } @@ -12160,6 +12175,7 @@ qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr driver, disk->src = source; source = NULL; disk->format = format; + disk->type = snap->type; if (persistDisk) { VIR_FREE(persistDisk->src); persistDisk->src = persistSource; -- 1.8.4.3

Add fields to hold information about network volumes for snapshots. RFC: Missing schema and tests. --- src/conf/snapshot_conf.c | 12 ++++++++---- src/conf/snapshot_conf.h | 15 +++++++++------ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index f6f170e..7ad605f 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -153,9 +153,9 @@ virDomainSnapshotDiskDefParseXML(xmlNodePtr node, if (virDomainDiskSourceDefParse(cur, backingtype, &def->file, - NULL, - NULL, - NULL, + &def->protocol, + &def->nhosts, + &def->hosts, NULL) < 0) goto cleanup; @@ -632,7 +632,11 @@ virDomainSnapshotDiskDefFormat(virBufferPtr buf, virDomainDiskSourceDefFormatInternal(buf, type, disk->file, - 0, 0, 0, NULL, 0, NULL, NULL, 0); + 0, + disk->protocol, + disk->nhosts, + disk->hosts, + 0, NULL, NULL, 0); virBufferAddLit(buf, " </disk>\n"); } diff --git a/src/conf/snapshot_conf.h b/src/conf/snapshot_conf.h index 241d63c..bcd92dc 100644 --- a/src/conf/snapshot_conf.h +++ b/src/conf/snapshot_conf.h @@ -48,12 +48,15 @@ enum virDomainSnapshotState { typedef struct _virDomainSnapshotDiskDef virDomainSnapshotDiskDef; typedef virDomainSnapshotDiskDef *virDomainSnapshotDiskDefPtr; struct _virDomainSnapshotDiskDef { - char *name; /* name matching the <target dev='...' of the domain */ - int index; /* index within snapshot->dom->disks that matches name */ - int snapshot; /* enum virDomainSnapshotLocation */ - int type; /* enum virDomainDiskType */ - char *file; /* new source file when snapshot is external */ - int format; /* enum virStorageFileFormat */ + char *name; /* name matching the <target dev='...' of the domain */ + int index; /* index within snapshot->dom->disks that matches name */ + int snapshot; /* enum virDomainSnapshotLocation */ + int type; /* enum virDomainDiskType */ + char *file; /* new source file when snapshot is external */ + int format; /* enum virStorageFileFormat */ + int protocol; /* network source protocol */ + size_t nhosts; /* network source hosts count */ + virDomainDiskHostDefPtr hosts; /* network source hosts */ }; /* Stores the complete snapshot metadata */ -- 1.8.4.3

This is a basic implementation of snapshots on gluster. Many things are lacking, especially cleanup after a failed snapshot. --- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_command.h | 9 ++++ src/qemu/qemu_driver.c | 106 ++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 109 insertions(+), 8 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 7a6e322..200ba45 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3826,7 +3826,7 @@ cleanup: } -static int +int qemuGetDriveSourceString(int type, const char *src, int protocol, diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 66c23cc..ec944ea 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -312,4 +312,13 @@ qemuParseKeywords(const char *str, int *retnkeywords, int allowEmptyValue); +int qemuGetDriveSourceString(int type, + const char *src, + int protocol, + size_t nhosts, + virDomainDiskHostDefPtr hosts, + const char *username, + const char *secret, + char **path); + #endif /* __QEMU_COMMAND_H__*/ diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e6d4f47..4aa88c8 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -11412,6 +11412,24 @@ cleanup: return ret; } + +static int +qemuDomainSnapshotDiskGetSourceString(virDomainSnapshotDiskDefPtr disk, + char **source) +{ + *source = NULL; + + return qemuGetDriveSourceString(qemuSnapshotDiskGetActualType(disk), + disk->file, + disk->protocol, + disk->nhosts, + disk->hosts, + NULL, + NULL, + source); +} + + typedef enum { VIR_DISK_CHAIN_NO_ACCESS, VIR_DISK_CHAIN_READ_ONLY, @@ -11792,6 +11810,29 @@ qemuDomainSnapshotPrepareDiskExternalOverlayActive(virDomainSnapshotDiskDefPtr d return 0; case VIR_DOMAIN_DISK_TYPE_NETWORK: + switch ((enum virDomainDiskProtocol) disk->protocol) { + case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER: + return 0; + + case VIR_DOMAIN_DISK_PROTOCOL_NBD: + case VIR_DOMAIN_DISK_PROTOCOL_RBD: + case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG: + case VIR_DOMAIN_DISK_PROTOCOL_ISCSI: + case VIR_DOMAIN_DISK_PROTOCOL_HTTP: + case VIR_DOMAIN_DISK_PROTOCOL_HTTPS: + case VIR_DOMAIN_DISK_PROTOCOL_FTP: + case VIR_DOMAIN_DISK_PROTOCOL_FTPS: + case VIR_DOMAIN_DISK_PROTOCOL_TFTP: + case VIR_DOMAIN_DISK_PROTOCOL_LAST: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("external active snapshots are not supported on " + "'network' disks using '%s' protocol"), + virDomainDiskProtocolTypeToString(disk->protocol)); + return -1; + + } + break; + case VIR_DOMAIN_DISK_TYPE_DIR: case VIR_DOMAIN_DISK_TYPE_VOLUME: case VIR_DOMAIN_DISK_TYPE_LAST: @@ -12101,6 +12142,9 @@ qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr driver, qemuDomainObjPrivatePtr priv = vm->privateData; char *device = NULL; char *source = NULL; + char *newsource = NULL; + virDomainDiskHostDefPtr newhosts = NULL; + virDomainDiskHostDefPtr persistHosts = NULL; int format = snap->format; const char *formatStr = NULL; char *persistSource = NULL; @@ -12114,8 +12158,7 @@ qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr driver, return -1; } - if (virAsprintf(&device, "drive-%s", disk->info.alias) < 0 || - (persistDisk && VIR_STRDUP(persistSource, source) < 0)) + if (virAsprintf(&device, "drive-%s", disk->info.alias) < 0) goto cleanup; /* XXX Here, we know we are about to alter disk->backingChain if @@ -12126,14 +12169,22 @@ qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr driver, virStorageFileFreeMetadata(disk->backingChain); disk->backingChain = NULL; + if (qemuDomainSnapshotDiskGetSourceString(snap, &source) < 0) + goto cleanup; + + if (VIR_STRDUP(newsource, snap->file) < 0) + goto cleanup; + + if (persistDisk && + VIR_STRDUP(persistSource, snap->file) < 0) + goto cleanup; + switch (snap->type) { case VIR_DOMAIN_DISK_TYPE_BLOCK: reuse = true; /* fallthrough */ case -1: /* type was not provided in snapshot conf */ case VIR_DOMAIN_DISK_TYPE_FILE: - if (VIR_STRDUP(source, snap->file) < 0) - goto cleanup; /* create the stub file and set selinux labels; manipulate disk in * place, in a way that can be reverted on failure. */ @@ -12153,6 +12204,27 @@ qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr driver, } break; + case VIR_DOMAIN_DISK_TYPE_NETWORK: + switch (snap->protocol) { + case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER: + if (!(newhosts = virDomainDiskHostDefCopy(snap->nhosts, snap->hosts))) + goto cleanup; + + if (persistDisk && + !(persistHosts = virDomainDiskHostDefCopy(snap->nhosts, snap->hosts))) + goto cleanup; + + break; + + default: + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("snapshots on volumes using '%s' protocol " + "are not supported"), + virDomainDiskProtocolTypeToString(snap->protocol)); + goto cleanup; + } + break; + default: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("snapshots are not supported on '%s' volumes"), @@ -12171,16 +12243,33 @@ qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr driver, /* Update vm in place to match changes. */ need_unlink = false; + VIR_FREE(disk->src); - disk->src = source; - source = NULL; + virDomainDiskHostDefFree(disk->nhosts, disk->hosts); + + disk->src = newsource; disk->format = format; disk->type = snap->type; + disk->protocol = snap->protocol; + disk->nhosts = snap->nhosts; + disk->hosts = newhosts; + + newsource = NULL; + newhosts = NULL; + if (persistDisk) { VIR_FREE(persistDisk->src); + virDomainDiskHostDefFree(persistDisk->nhosts, persistDisk->hosts); + persistDisk->src = persistSource; - persistSource = NULL; persistDisk->format = format; + persistDisk->type = snap->type; + persistDisk->protocol = snap->protocol; + persistDisk->nhosts = snap->nhosts; + persistDisk->hosts = persistHosts; + + persistSource = NULL; + persistHosts = NULL; } cleanup: @@ -12188,7 +12277,10 @@ cleanup: VIR_WARN("unable to unlink just-created %s", source); VIR_FREE(device); VIR_FREE(source); + VIR_FREE(newsource); VIR_FREE(persistSource); + virDomainDiskHostDefFree(snap->nhosts, newhosts); + virDomainDiskHostDefFree(snap->nhosts, persistHosts); return ret; } -- 1.8.4.3
participants (1)
-
Peter Krempa