If you take a checkpoint snapshot of a running domain, then pause
qemu, then restore the snapshot, the result should be a running
domain, but the code was leaving things paused. Furthermore, if
you take a checkpoint of a paused domain, then run, then restore,
there was a brief but non-deterministic window of time where the
domain was running rather than paused. Fix both of these
discrepancies by always pausing before restoring.
* src/qemu/qemu_driver.c (qemuDomainRevertToSnapshot): Always
pause before reversion.
---
src/qemu/qemu_driver.c | 51 +++++++++++++++++++++++++++++++----------------
1 files changed, 33 insertions(+), 18 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 1077843..2f5af87 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -8760,44 +8760,59 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr
snapshot,
if (snap->def->state == VIR_DOMAIN_RUNNING
|| snap->def->state == VIR_DOMAIN_PAUSED) {
-
+ /* When using the loadvm monitor command, qemu does not know
+ * whether to pause or run the reverted domain, and just stays
+ * in the same state as before the monitor command, whether
+ * that is paused or running. We always pause before loadvm,
+ * to have finer control. */
if (virDomainObjIsActive(vm)) {
priv = vm->privateData;
+ if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
+ if (qemuProcessStopCPUs(driver, vm,
+ VIR_DOMAIN_PAUSED_FROM_SNAPSHOT,
+ QEMU_ASYNC_JOB_NONE) < 0)
+ goto endjob;
+ /* Create an event now in case the restore fails, so
+ * that user will be alerted that they are now paused.
+ * If restore later succeeds to a running state, we
+ * replace this event with another. */
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_SUSPENDED,
+
VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
+ }
qemuDomainObjEnterMonitorWithDriver(driver, vm);
rc = qemuMonitorLoadSnapshot(priv->mon, snap->def->name);
qemuDomainObjExitMonitorWithDriver(driver, vm);
- if (rc < 0)
+ if (rc < 0) {
+ /* XXX resume domain if it was running before the
+ * failed loadvm attempt? */
goto endjob;
+ }
} else {
if (qemuDomainSnapshotSetCurrentActive(vm, driver->snapshotDir) < 0)
goto endjob;
rc = qemuProcessStart(snapshot->domain->conn, driver, vm, NULL,
- false, false, -1, NULL, VIR_VM_OP_CREATE);
+ true, false, -1, NULL, VIR_VM_OP_CREATE);
virDomainAuditStart(vm, "from-snapshot", rc >= 0);
+ if (rc < 0)
+ goto endjob;
if (qemuDomainSnapshotSetCurrentInactive(vm,
driver->snapshotDir) < 0)
goto endjob;
- if (rc < 0)
- goto endjob;
}
+ /* Touch up domain state. */
if (snap->def->state == VIR_DOMAIN_PAUSED) {
- /* qemu unconditionally starts the domain running again after
- * loadvm, so let's pause it to keep consistency
- * XXX we should have used qemuProcessStart's start_paused instead
- */
- rc = qemuProcessStopCPUs(driver, vm,
- VIR_DOMAIN_PAUSED_FROM_SNAPSHOT,
- QEMU_ASYNC_JOB_NONE);
+ virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
+ VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
+ } else {
+ rc = qemuProcessStartCPUs(driver, vm, snapshot->domain->conn,
+ VIR_DOMAIN_RUNNING_FROM_SNAPSHOT,
+ QEMU_ASYNC_JOB_NONE);
if (rc < 0)
goto endjob;
- event = virDomainEventNewFromObj(vm,
- VIR_DOMAIN_EVENT_SUSPENDED,
- VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
- } else {
- virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
- VIR_DOMAIN_RUNNING_FROM_SNAPSHOT);
+ virDomainEventFree(event);
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
--
1.7.4.4