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 | 75 ++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 73 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 89aa56c..428ba0f 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -11222,6 +11222,61 @@ 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;
+ char *file;
+
+ 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);
+ if (virAsprintf(&device, "drive-%s",
+ vm->def->disks[i]->info.alias) < 0) {
+ virReportOOMError();
+ break;
+ }
+ file = pivot ? snap->def->disks[i].mirror :
snap->def->disks[i].file;
+ if (qemuMonitorDriveReopen(priv->mon, device, file,
+ 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;
+ if (pivot)
+ snap->def->disks[i].file = snap->def->disks[i].mirror;
+ snap->def->disks[i].mirror = NULL;
+ }
+ VIR_FREE(device);
+ 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)
{
@@ -11234,10 +11289,14 @@ static int qemuDomainSnapshotDelete(virDomainSnapshotPtr
snapshot,
struct snap_reparent rep;
bool metadata_only = !!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY);
int external = 0;
+ bool mirror_abort = (flags & VIR_DOMAIN_SNAPSHOT_DELETE_MIRROR_ABORT) != 0;
+ bool mirror_pivot = (flags & VIR_DOMAIN_SNAPSHOT_DELETE_MIRROR_PIVOT) != 0;
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);
@@ -11262,8 +11321,16 @@ 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;
+ }
+ flags |= VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY;
+ } 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;
}
@@ -11286,6 +11353,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