For now, disk migration via mirroring is not implemented. But when we do implement it, we have to deal with the fact that qemu does not provide an easy way to re-start a qemu process with mirroring still intact (it _might_ be possible by using qemu -S then an initial 'drive-mirror' with disk reuse before starting the domain, but that gets hairy). Even something like 'virDomainSave' becomes hairy, if you realize the implications that 'virDomainRestore' would be stuck with recreating the same mirror layout. But if we step back and look at the bigger picture, we realize that the initial client of live storage migration via disk mirroring is oVirt, which always uses transient domains, and that if a transient domain is destroyed while a mirror exists, oVirt can easily restart the storage migration by creating a new domain that visits just the source storage, with no loss in data. We can make life a lot easier by being cowards, and forbidding certain operations on a domain. This patch guarantees that there will be at most one snapshot with disk mirroring, that it will always be the current snapshot, and that the user cannot redefine that snapshot nor hot-plug or hot-unplug any domain disks - for now, the only way to delete such a snapshot is by destroying the transient domain it is attached to. A future patch will add the ability to also delete such snapshots under a condition of a flag which says how to end the mirroring with the 'drive-reopen' monitor command; and once that is in place, then we can finally implement creation of the mirroring via 'drive-mirror'. With just this patch applied, the only way you can ever get virDomainHasDiskMirror to return true is by manually playing with the libvirt internal directory and then restarting libvirtd. * src/conf/domain_conf.h (virDomainSnapshotHasDiskMirror) (virDomainHasDiskMirror): New prototypes. * src/conf/domain_conf.c (virDomainSnapshotHasDiskMirror) (virDomainHasDiskMirror): Implement them. * src/libvirt_private.syms (domain_conf.h): Export them. * src/qemu/qemu_driver.c (qemuDomainSaveInternal) (qemuDomainSnapshotCreateXML, qemuDomainRevertToSnapshot) (qemuDomainSnapshotDelete, qemuDomainAttachDeviceDiskLive) (qemuDomainDetachDeviceDiskLive): Use it. (qemuDomainSnapshotLoad): Allow libvirtd restarts with active disk mirroring, but sanity check for only a current image with mirrors. --- src/conf/domain_conf.c | 20 +++++++++++++++++ src/conf/domain_conf.h | 2 + src/libvirt_private.syms | 2 + src/qemu/qemu_driver.c | 53 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 76 insertions(+), 1 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f84304c..85abf32 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -13652,6 +13652,26 @@ cleanup: return ret; } +/* Determine if the given snapshot contains a disk mirror. */ +bool +virDomainSnapshotHasDiskMirror(virDomainSnapshotDefPtr snapshot) +{ + int i; + for (i = 0; i < snapshot->ndisks; i++) + if (snapshot->disks[i].mirror) + return true; + return false; +} + +/* Determine if the given domain has a current snapshot that contains + * a disk mirror. */ +bool virDomainHasDiskMirror(virDomainObjPtr vm) +{ + if (!vm->current_snapshot) + return false; + return virDomainSnapshotHasDiskMirror(vm->current_snapshot->def); +} + char *virDomainSnapshotDefFormat(const char *domain_uuid, virDomainSnapshotDefPtr def, unsigned int flags, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 01a504b..1ea7332 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1706,6 +1706,7 @@ char *virDomainSnapshotDefFormat(const char *domain_uuid, int virDomainSnapshotAlignDisks(virDomainSnapshotDefPtr snapshot, int default_snapshot, bool require_match); +bool virDomainSnapshotHasDiskMirror(virDomainSnapshotDefPtr snapshot); virDomainSnapshotObjPtr virDomainSnapshotAssignDef(virDomainSnapshotObjListPtr snapshots, const virDomainSnapshotDefPtr def); @@ -1931,6 +1932,7 @@ virDomainDiskDefPtr virDomainDiskRemove(virDomainDefPtr def, size_t i); virDomainDiskDefPtr virDomainDiskRemoveByName(virDomainDefPtr def, const char *name); +bool virDomainHasDiskMirror(virDomainObjPtr vm); int virDomainNetIndexByMac(virDomainDefPtr def, const unsigned char *mac); int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 9a718b4..6739733 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -358,6 +358,7 @@ virDomainGraphicsSpiceZlibCompressionTypeFromString; virDomainGraphicsSpiceZlibCompressionTypeToString; virDomainGraphicsTypeFromString; virDomainGraphicsTypeToString; +virDomainHasDiskMirror; virDomainHostdevDefAlloc; virDomainHostdevDefClear; virDomainHostdevDefFree; @@ -450,6 +451,7 @@ virDomainSnapshotDropParent; virDomainSnapshotFindByName; virDomainSnapshotForEachChild; virDomainSnapshotForEachDescendant; +virDomainSnapshotHasDiskMirror; virDomainSnapshotObjListGetNames; virDomainSnapshotObjListGetNamesFrom; virDomainSnapshotObjListNum; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 6dd1b32..89aa56c 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -320,7 +320,8 @@ static void qemuDomainSnapshotLoad(void *payload, char ebuf[1024]; unsigned int flags = (VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE | VIR_DOMAIN_SNAPSHOT_PARSE_DISKS | - VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL); + VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL | + VIR_DOMAIN_SNAPSHOT_PARSE_MIRROR); virDomainObjLock(vm); if (virAsprintf(&snapDir, "%s/%s", baseDir, vm->def->name) < 0) { @@ -373,6 +374,16 @@ static void qemuDomainSnapshotLoad(void *payload, VIR_FREE(xmlStr); continue; } + if (!def->current && virDomainSnapshotHasDiskMirror(def)) { + /* Someone must have hand-modified the directory; ignore them. */ + VIR_ERROR(_("Disk mirroring unexpected since snapshot file '%s' " + "does not claim to be the current snapshot"), + fullpath); + virDomainSnapshotDefFree(def); + VIR_FREE(fullpath); + VIR_FREE(xmlStr); + continue; + } snap = virDomainSnapshotAssignDef(&vm->snapshots, def); if (snap == NULL) { @@ -2536,6 +2547,11 @@ qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom, "%s", _("domain is marked for auto destroy")); goto cleanup; } + if (virDomainHasDiskMirror(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("domain has active disk mirrors")); + goto cleanup; + } memset(&header, 0, sizeof(header)); memcpy(header.magic, QEMUD_SAVE_PARTIAL, sizeof(header.magic)); @@ -5067,6 +5083,12 @@ qemuDomainAttachDeviceDiskLive(virConnectPtr conn, virCgroupPtr cgroup = NULL; int ret = -1; + if (virDomainHasDiskMirror(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("domain has active disk mirrors")); + goto end; + } + if (disk->driverName != NULL && !STREQ(disk->driverName, "qemu")) { qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("unsupported driver name '%s' for disk '%s'"), @@ -5217,6 +5239,12 @@ qemuDomainDetachDeviceDiskLive(struct qemud_driver *driver, virDomainDiskDefPtr disk = dev->data.disk; int ret = -1; + if (virDomainHasDiskMirror(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("domain has active disk mirrors")); + return -1; + } + switch (disk->device) { case VIR_DOMAIN_DISK_DEVICE_DISK: case VIR_DOMAIN_DISK_DEVICE_LUN: @@ -10239,6 +10267,12 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain, "%s", _("domain is marked for auto destroy")); goto cleanup; } + if (virDomainHasDiskMirror(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("domain has active disk mirrors")); + goto cleanup; + } + if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) { qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", _("cannot halt after transient domain snapshot")); @@ -10847,6 +10881,12 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, goto cleanup; } + if (virDomainHasDiskMirror(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("domain has active disk mirrors")); + goto cleanup; + } + snap = virDomainSnapshotFindByName(&vm->snapshots, snapshot->name); if (!snap) { qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, @@ -11216,6 +11256,17 @@ static int qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot, goto cleanup; } + if (virDomainHasDiskMirror(vm)) { + if (snap != vm->current_snapshot) { + qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("domain has active disk mirrors")); + goto cleanup; + } + qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("deletion of active disk mirrors unimplemented")); + goto cleanup; + } + if (!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY)) { if (!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) && snap->def->state == VIR_DOMAIN_DISK_SNAPSHOT) -- 1.7.7.6 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list