This just uses the existing plumping to update the guest XML to point
at the chosen snapshot disk images. It requires the VM to be inactive.
---
Reverting to a snapshot with children and then running the guest is
probably unsafe, since the backing image will change state on the child
snapshots. How do internal snapshots work around this?
src/qemu/qemu_driver.c | 72 ++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 64 insertions(+), 8 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 9bf89bb..53f5340 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -11205,6 +11205,65 @@ qemuDomainSnapshotRevertInactive(struct qemud_driver *driver,
return ret > 0 ? -1 : ret;
}
+/* The domain is expected to be locked */
+static int qemuDomainRevertToSnapshotDisk(virDomainSnapshotObjPtr snap,
+ virDomainObjPtr vm,
+ virDomainDefPtr config,
+ unsigned int flags)
+{
+ int ret = -1;
+ int i;
+
+ if (virDomainObjIsActive(vm)) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("domain must be stopped to revert to a "
+ "disk only snapshot"));
+ goto cleanup;
+ }
+
+ if (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
+ VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("domain can only be shutoff after reverting to a"
+ "disk only snapshot"));
+ goto cleanup;
+ }
+
+ if (!config) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("domain XML must be present in the snapshot metadata"));
+ goto cleanup;
+ }
+
+ for (i = 0; i < snap->def->ndisks; i++) {
+ virDomainDiskDefPtr vmdisk = config->disks[i];
+ virDomainSnapshotDiskDefPtr snapdisk = &(snap->def->disks[i]);
+ char *src = NULL;
+ char *type = NULL;
+
+ if (snapdisk->snapshot == VIR_DOMAIN_DISK_SNAPSHOT_NO)
+ continue;
+
+ if (!(src = strdup(snapdisk->file)) ||
+ !(type = strdup(snapdisk->driverType))) {
+ virReportOOMError();
+ VIR_FREE(src);
+ VIR_FREE(type);
+ goto cleanup;
+ }
+
+ VIR_FREE(vmdisk->src);
+ vmdisk->src = src;
+ VIR_FREE(vmdisk->driverType);
+ vmdisk->driverType = type;
+ }
+
+ virDomainObjAssignDef(vm, config, false);
+ ret = 0;
+cleanup:
+ return ret;
+}
+
static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
unsigned int flags)
{
@@ -11265,12 +11324,6 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr
snapshot,
"to revert to inactive snapshot"));
goto cleanup;
}
- if (snap->def->state == VIR_DOMAIN_DISK_SNAPSHOT) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("revert to external disk snapshot not supported "
- "yet"));
- goto cleanup;
- }
if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
if (!snap->def->dom) {
virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY,
@@ -11289,7 +11342,6 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr
snapshot,
}
}
-
if (vm->current_snapshot) {
vm->current_snapshot->def->current = false;
if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
@@ -11325,6 +11377,11 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr
snapshot,
if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
goto cleanup;
+ if (snap->def->state == VIR_DOMAIN_DISK_SNAPSHOT) {
+ ret = qemuDomainRevertToSnapshotDisk(snap, vm, config, flags);
+ goto endjob;
+ }
+
if (snap->def->state == VIR_DOMAIN_RUNNING
|| snap->def->state == VIR_DOMAIN_PAUSED) {
/* Transitions 2, 3, 5, 6, 8, 9 */
@@ -11522,7 +11579,6 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr
snapshot,
}
ret = 0;
-
endjob:
if (vm && qemuDomainObjEndJob(driver, vm) == 0)
vm = NULL;
--
1.7.11.2