Delete a mirrored snapshot by picking which of the two files in the
mirror to reopen. This is not atomic, so we update the snapshot
in place as we iterate through each successful disk. Since we limited
mirrored snapshots to transient domains, there is no persistent
configuration to update. This mode implies deleting the snapshot
metadata but preserving the new file.
* src/qemu/qemu_driver.c (qemuDomainSnapshotDelete): Honor new
flags.
(qemuDomainSnapshotDeleteMirror): New helper function.
---
src/qemu/qemu_driver.c | 85 +++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 81 insertions(+), 4 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 5b1ed87..4ce31a3 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -11283,6 +11283,66 @@ qemuDomainSnapshotReparentChildren(void *payload,
rep->driver->snapshotDir);
}
+/* Must be called while holding a job. */
+static int
+qemuDomainSnapshotDeleteMirror(struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainSnapshotObjPtr snap,
+ bool pivot)
+{
+ int i;
+ int ret = 0;
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ char *device = NULL;
+ const char *dest;
+ char *file = NULL;
+
+ if (!virDomainObjIsActive(vm)) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("domain is not running"));
+ return -1;
+ }
+
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
+
+ for (i = 0; i < snap->def->ndisks; i++) {
+ if (!snap->def->disks[i].mirror)
+ continue;
+ VIR_FREE(device);
+ VIR_FREE(file);
+ dest = pivot ? snap->def->disks[i].mirror :
snap->def->disks[i].file;
+ if (virAsprintf(&device, "drive-%s",
+ vm->def->disks[i]->info.alias) < 0 ||
+ (file = strdup(dest)) == NULL) {
+ virReportOOMError();
+ break;
+ }
+ if (qemuMonitorDriveReopen(priv->mon, device, dest,
+ snap->def->disks[i].driverType) < 0)
+ break;
+ /* TODO: Release lock and reset label. */
+
+ VIR_FREE(vm->def->disks[i]->src);
+ vm->def->disks[i]->src = file;
+ file = NULL;
+ if (pivot)
+ snap->def->disks[i].file = snap->def->disks[i].mirror;
+ snap->def->disks[i].mirror = NULL;
+ }
+ VIR_FREE(device);
+ VIR_FREE(file);
+ if (i < snap->def->ndisks)
+ ret = -1;
+
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+
+ if (ret < 0 &&
+ qemuDomainSnapshotWriteMetadata(vm, snap, driver->snapshotDir) < 0)
+ VIR_WARN("failed writing snapshot '%s' after partial mirror
deletion",
+ snap->def->name);
+ return ret;
+}
+
static int qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
unsigned int flags)
{
@@ -11293,12 +11353,16 @@ static int qemuDomainSnapshotDelete(virDomainSnapshotPtr
snapshot,
char uuidstr[VIR_UUID_STRING_BUFLEN];
struct qemu_snap_remove rem;
struct snap_reparent rep;
- bool metadata_only = !!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY);
int external = 0;
+ bool metadata_only = !!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY);
+ bool mirror_abort = !!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_MIRROR_ABORT);
+ bool mirror_pivot = !!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_MIRROR_PIVOT);
virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY |
- VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1);
+ VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY |
+ VIR_DOMAIN_SNAPSHOT_DELETE_MIRROR_ABORT |
+ VIR_DOMAIN_SNAPSHOT_DELETE_MIRROR_PIVOT, -1);
qemuDriverLock(driver);
virUUIDFormat(snapshot->domain->uuid, uuidstr);
@@ -11323,12 +11387,21 @@ static int qemuDomainSnapshotDelete(virDomainSnapshotPtr
snapshot,
_("domain has active disk mirrors"));
goto cleanup;
}
+ if (!(mirror_abort || mirror_pivot)) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("must specify whether to abort or pivot "
+ "mirrors before deleting snapshot"));
+ goto cleanup;
+ }
+ metadata_only = true;
+ flags = 0;
+ } else if (mirror_abort || mirror_pivot) {
qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("deletion of active disk mirrors unimplemented"));
+ _("snapshot has no disk mirrors"));
goto cleanup;
}
- if (!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY)) {
+ if (!metadata_only) {
if (!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) &&
snap->def->state == VIR_DOMAIN_DISK_SNAPSHOT)
external++;
@@ -11347,6 +11420,10 @@ static int qemuDomainSnapshotDelete(virDomainSnapshotPtr
snapshot,
if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
goto cleanup;
+ if ((mirror_abort || mirror_pivot) &&
+ qemuDomainSnapshotDeleteMirror(driver, vm, snap, mirror_pivot) < 0)
+ goto endjob;
+
if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) {
rem.driver = driver;
--
1.7.7.6