This patch adds limited support for deleting external snaphots. The
machine must not be active and only whole subtrees of snapshots can be
deleted as reparenting was not yet implemented for external snapshots.
---
This patch introduces a possible segfault, but I haven't had time to chase it.
---
src/qemu/qemu_domain.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++---
src/qemu/qemu_driver.c | 23 ++++++++--
2 files changed, 135 insertions(+), 10 deletions(-)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index a5592b9..e8f9aed 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -1724,13 +1724,102 @@ qemuDomainSnapshotForEachQcow2(struct qemud_driver *driver,
op, try_all, def->ndisks);
}
-/* Discard one snapshot (or its metadata), without reparenting any children. */
-int
-qemuDomainSnapshotDiscard(struct qemud_driver *driver,
- virDomainObjPtr vm,
- virDomainSnapshotObjPtr snap,
- bool update_current,
- bool metadata_only)
+/* Discard one external snapshot (or its metadata), without reparenting any children */
+static int
+qemuDomainSnapshotDiscardExternal(struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainSnapshotObjPtr snap,
+ bool update_current,
+ bool metadata_only)
+{
+ char *snapFile = NULL;
+ int i;
+ int ret = -1;
+ virDomainSnapshotObjPtr parentsnap = NULL;
+
+ if (!metadata_only) {
+ if (virDomainObjIsActive(vm)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Can't delete snapshot '%s'. Domain
'%s' is active."),
+ snap->def->name, vm->def->name);
+ goto cleanup;
+ }
+
+ if (snap->def->file) {
+ if (unlink(snap->def->file) < 0) {
+ virReportSystemError(errno,
+ _("Failed to remove memory checkpoint "
+ "save file '%s'"),
snap->def->file);
+ goto cleanup;
+ }
+ VIR_FREE(snap->def->file);
+ }
+
+ for (i = 0; i < snap->def->ndisks; i++) {
+ virDomainSnapshotDiskDefPtr disk = &(snap->def->disks[i]);
+ if (disk->file && unlink(disk->file) < 0) {
+ virReportSystemError(errno,
+ _("Failed to remove disk snapshot file
'%s'"),
+ disk->file);
+ goto cleanup;
+ }
+ VIR_FREE(disk->file);
+ }
+ }
+
+ if (snap == vm->current_snapshot) {
+ if (update_current && snap->def->parent) {
+ parentsnap = virDomainSnapshotFindByName(vm->snapshots,
+ snap->def->parent);
+ if (!parentsnap) {
+ VIR_WARN("missing parent snapshot matching name '%s'",
+ snap->def->parent);
+ } else {
+ parentsnap->def->current = true;
+
+ if (qemuDomainSnapshotWriteMetadata(vm, parentsnap,
+ driver->snapshotDir) < 0) {
+ VIR_WARN("failed to set parent snapshot '%s' as
current",
+ snap->def->parent);
+ parentsnap->def->current = false;
+ parentsnap = NULL;
+ }
+ }
+ }
+ vm->current_snapshot = parentsnap;
+ }
+
+ if (virAsprintf(&snapFile, "%s/%s/%s.xml", driver->snapshotDir,
+ vm->def->name, snap->def->name) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (unlink(snapFile) < 0)
+ VIR_WARN("Failed to unlink %s", snapFile);
+ virDomainSnapshotObjListRemove(vm->snapshots, snap);
+
+ ret = 0;
+
+cleanup:
+ if (ret < 0 && !snapFile &&
+ qemuDomainSnapshotWriteMetadata(vm, snap, driver->snapshotDir) < 0)
+ VIR_WARN("Failed to store modified snapshot config");
+
+ VIR_FREE(snapFile);
+
+ return ret;
+}
+
+/* Discard one internal snapshot (or its metadata),
+ * without reparenting any children.
+ */
+static int
+qemuDomainSnapshotDiscardInternal(struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainSnapshotObjPtr snap,
+ bool update_current,
+ bool metadata_only)
{
char *snapFile = NULL;
int ret = -1;
@@ -1791,6 +1880,25 @@ cleanup:
return ret;
}
+/* Discard one snapshot (or its metadata), without reparenting any children. */
+int
+qemuDomainSnapshotDiscard(struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainSnapshotObjPtr snap,
+ bool update_current,
+ bool metadata_only)
+{
+ int ret;
+
+ if (virDomainSnapshotIsExternal(snap))
+ ret = qemuDomainSnapshotDiscardExternal(driver, vm, snap, update_current,
metadata_only);
+ else
+ ret = qemuDomainSnapshotDiscardInternal(driver, vm, snap, update_current,
metadata_only);
+
+ return ret;
+}
+
+
/* Hash iterator callback to discard multiple snapshots. */
void qemuDomainSnapshotDiscardAll(void *payload,
const void *name ATTRIBUTE_UNUSED,
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 44bf6dc..46b7e3a 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -12376,6 +12376,13 @@ qemuDomainSnapshotReparentChildren(void *payload,
return;
}
+ if (virDomainSnapshotIsExternal(snap)) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("Reparenting of external snapshots is not
implemented"));
+ rep->err = -1;
+ return;
+ }
+
VIR_FREE(snap->def->parent);
snap->parent = rep->parent;
@@ -12433,10 +12440,20 @@ static int qemuDomainSnapshotDelete(virDomainSnapshotPtr
snapshot,
virDomainSnapshotForEachDescendant(snap,
qemuDomainSnapshotCountExternal,
&external);
- if (external) {
+ if (external &&
+ virDomainObjIsActive(vm)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("deletion of %d external disk snapshots not "
- "supported yet"), external);
+ _("deletion of %d external disk snapshots is "
+ "supported only on inactive guests"), external);
+ goto cleanup;
+ }
+
+ if (external &&
+ !(flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
+ VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY))) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("only deletion of external snapshot subtrees is "
+ "implemented"));
goto cleanup;
}
}
--
1.7.12.4