return ret;
}
-static virDomainSnapshotPtr qemuDomainSnapshotCreateXML(virDomainPtr domain,
- const char *xmlDesc,
- unsigned int flags)
+static virDomainSnapshotPtr
+qemuDomainSnapshotCreateXML(virDomainPtr domain,
+ const char *xmlDesc,
+ unsigned int flags)
{
struct qemud_driver *driver = domain->conn->privateData;
virDomainObjPtr vm = NULL;
+ char *xml = NULL;
virDomainSnapshotObjPtr snap = NULL;
virDomainSnapshotPtr snapshot = NULL;
char uuidstr[VIR_UUID_STRING_BUFLEN];
goto cleanup;
}
- /* in a perfect world, we would allow qemu to tell us this. The problem
- * is that qemu only does this check device-by-device; so if you had a
- * domain that booted from a large qcow2 device, but had a secondary raw
- * device attached, you wouldn't find out that you can't snapshot your
- * guest until *after* it had spent the time to snapshot the boot device.
- * This is probably a bug in qemu, but we'll work around it here for now.
- */
- if (!qemuDomainSnapshotIsAllowed(vm))
- goto cleanup;
-
if (!(def = virDomainSnapshotDefParseString(xmlDesc, driver->caps,
QEMU_EXPECTED_VIRT_TYPES,
parse_flags)))
}
/* Check that any replacement is compatible */
+ if (def->dom &&
+ memcmp(def->dom->uuid, domain->uuid, VIR_UUID_BUFLEN)) {
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ _("definition for snapshot %s must use uuid %s"),
+ def->name, uuidstr);
+ goto cleanup;
+ }
other = virDomainSnapshotFindByName(&vm->snapshots, def->name);
if (other) {
if ((other->def->state == VIR_DOMAIN_RUNNING ||
def->name);
goto cleanup;
}
- /* XXX Ensure ABI compatibility before replacing anything. */
+ if (other->def->dom) {
+ if (def->dom) {
+ if (!virDomainDefCheckABIStability(other->def->dom,
+ def->dom))
+ goto cleanup;
+ } else {
+ /* Transfer the domain def */
+ def->dom = other->def->dom;
+ other->def->dom = NULL;
+ }
+ }
if (other == vm->current_snapshot) {
update_current = true;
vm->current_snapshot = NULL;
* qemu-img output to check that def->name matches at
* least one qcow2 snapshot name? */
}
+ } else {
+ /* Easiest way to clone inactive portion of vm->def is via
+ * conversion in and back out of xml. */
+ if (!(xml = virDomainDefFormat(vm->def, (VIR_DOMAIN_XML_INACTIVE |
+ VIR_DOMAIN_XML_SECURE))) ||
+ !(def->dom = virDomainDefParseString(driver->caps, xml,
+ QEMU_EXPECTED_VIRT_TYPES,
+ VIR_DOMAIN_XML_INACTIVE)))
+ goto cleanup;
}
+ /* in a perfect world, we would allow qemu to tell us this. The problem
+ * is that qemu only does this check device-by-device; so if you had a
+ * domain that booted from a large qcow2 device, but had a secondary raw
+ * device attached, you wouldn't find out that you can't snapshot your
+ * guest until *after* it had spent the time to snapshot the boot device.
+ * This is probably a bug in qemu, but we'll work around it here for now.
+ */
+ if (!qemuDomainSnapshotIsAllowed(vm))
+ goto cleanup;
+
if (!(snap = virDomainSnapshotAssignDef(&vm->snapshots, def)))
goto cleanup;
def = NULL;
virDomainObjUnlock(vm);
}
virDomainSnapshotDefFree(def);
+ VIR_FREE(xml);
qemuDriverUnlock(driver);
return snapshot;
}
int detail;
qemuDomainObjPrivatePtr priv;
int rc;
+ virDomainDefPtr config = NULL;
virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED, -1);
* in the failure cases where we know there was no change? */
}
+ /* Prepare to copy the snapshot inactive xml as the config of this
+ * domain. Easiest way is by a round trip through xml.
+ *
+ * XXX Should domain snapshots track live xml rather
+ * than inactive xml? */
snap->def->current = true;
+ if (snap->def->dom) {
+ char *xml;
+ if (!(xml = virDomainDefFormat(snap->def->dom,
+ (VIR_DOMAIN_XML_INACTIVE |
+ VIR_DOMAIN_XML_SECURE))))
+ goto cleanup;
+ config = virDomainDefParseString(driver->caps, xml,
+ QEMU_EXPECTED_VIRT_TYPES,
+ VIR_DOMAIN_XML_INACTIVE);
+ VIR_FREE(xml);
+ if (!config)
+ goto cleanup;
+ } else {
+ /* XXX Fail if VIR_DOMAIN_REVERT_FORCE is not set, rather than
+ * blindly hoping for the best. */
+ VIR_WARN("snapshot is lacking rollback information for domain '%s'",
+ snap->def->name);
+ }
if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
goto cleanup;
* to have finer control. */
if (virDomainObjIsActive(vm)) {
/* Transitions 5, 6, 8, 9 */
+ /* Check for ABI compatibility. */
+ if (config && !virDomainDefCheckABIStability(vm->def, config)) {
+ /* XXX Add VIR_DOMAIN_REVERT_FORCE to permit killing
+ * and restarting a new qemu, since loadvm monitor
+ * command won't work. */
+ goto endjob;
+ }
+
priv = vm->privateData;
if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
/* Transitions 5, 6 */
* failed loadvm attempt? */
goto endjob;
}
+ if (config)
+ virDomainObjAssignDef(vm, config, false);
} else {
/* Transitions 2, 3 */
was_stopped = true;
+ if (config)
+ virDomainObjAssignDef(vm, config, false);
+
rc = qemuProcessStart(snapshot->domain->conn, driver, vm, NULL,
true, false, -1, NULL, snap,
VIR_VM_OP_CREATE);
}
goto endjob;
}
+ if (config)
+ virDomainObjAssignDef(vm, config, false);
if (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) {