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 | 15 ++++++++++++++- src/conf/domain_conf.h | 1 + src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 42 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index fd9fd2c..30cea8d 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -7194,7 +7194,9 @@ virDomainHasDiskMirror(virDomainObjPtr vm) for (i = 0; i < vm->def->ndisks; i++) if (vm->def->disks[i]->mirror) return true; - return false; + if (!vm->current_snapshot) + return false; + return virDomainSnapshotHasDiskMirror(vm->current_snapshot->def); } int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net) @@ -13833,6 +13835,17 @@ 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; +} + 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 a25cd1a..e56d7c9 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1731,6 +1731,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); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 4ed2f0c..8ecd0eb 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -447,6 +447,7 @@ virDomainSnapshotDropParent; virDomainSnapshotFindByName; virDomainSnapshotForEachChild; virDomainSnapshotForEachDescendant; +virDomainSnapshotHasDiskMirror; virDomainSnapshotObjListGetNames; virDomainSnapshotObjListGetNamesFrom; virDomainSnapshotObjListNum; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index dd49cb9..5b1ed87 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) { @@ -5117,6 +5128,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'"), @@ -5267,6 +5284,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: @@ -10914,6 +10937,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, @@ -11288,6 +11317,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