mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
snapshot: allow halting after snapshot
Since a snapshot is fully recoverable, it is useful to have a snapshot as a means of hibernating a guest, then reverting to the snapshot to wake the guest up. This mode of usage is similar to 'virsh save/virsh restore', except that virsh save uses an external file while virsh snapshot keeps the vm state internal to a qcow2 file. However, it only works on persistent domains. In the usage pattern of snapshot/revert for hibernating a guest, there is no need to keep the guest running between the two points in time, especially since that would generate runtime state that would just be discarded. Add a flag to make it possible to stop the domain after the snapshot has completed. * include/libvirt/libvirt.h.in (VIR_DOMAIN_SNAPSHOT_CREATE_HALT): New flag. * src/libvirt.c (virDomainSnapshotCreateXML): Document it. * src/qemu/qemu_driver.c (qemuDomainSnapshotCreateXML) (qemuDomainSnapshotCreateActive): Implement it.
This commit is contained in:
parent
ddc882733a
commit
6f66423e17
@ -2567,6 +2567,8 @@ typedef enum {
|
|||||||
snapshot current */
|
snapshot current */
|
||||||
VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA = (1 << 2), /* Make snapshot without
|
VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA = (1 << 2), /* Make snapshot without
|
||||||
remembering it */
|
remembering it */
|
||||||
|
VIR_DOMAIN_SNAPSHOT_CREATE_HALT = (1 << 3), /* Stop running guest
|
||||||
|
after snapshot */
|
||||||
} virDomainSnapshotCreateFlags;
|
} virDomainSnapshotCreateFlags;
|
||||||
|
|
||||||
/* Take a snapshot of the current VM state */
|
/* Take a snapshot of the current VM state */
|
||||||
|
@ -15637,6 +15637,12 @@ error:
|
|||||||
* the just-created snapshot has its metadata deleted. This flag is
|
* the just-created snapshot has its metadata deleted. This flag is
|
||||||
* incompatible with VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE.
|
* incompatible with VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE.
|
||||||
*
|
*
|
||||||
|
* If @flags includes VIR_DOMAIN_SNAPSHOT_CREATE_HALT, then the domain
|
||||||
|
* will be inactive after the snapshot completes, regardless of whether
|
||||||
|
* it was active before; otherwise, a running domain will still be
|
||||||
|
* running after the snapshot. This flag is invalid on transient domains,
|
||||||
|
* and is incompatible with VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE.
|
||||||
|
*
|
||||||
* Returns an (opaque) virDomainSnapshotPtr on success, NULL on failure.
|
* Returns an (opaque) virDomainSnapshotPtr on success, NULL on failure.
|
||||||
*/
|
*/
|
||||||
virDomainSnapshotPtr
|
virDomainSnapshotPtr
|
||||||
@ -15680,6 +15686,12 @@ virDomainSnapshotCreateXML(virDomainPtr domain,
|
|||||||
_("redefine and no metadata flags are mutually exclusive"));
|
_("redefine and no metadata flags are mutually exclusive"));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) &&
|
||||||
|
(flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
|
||||||
|
virLibDomainError(VIR_ERR_INVALID_ARG,
|
||||||
|
_("redefine and halt flags are mutually exclusive"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
if (conn->driver->domainSnapshotCreateXML) {
|
if (conn->driver->domainSnapshotCreateXML) {
|
||||||
virDomainSnapshotPtr ret;
|
virDomainSnapshotPtr ret;
|
||||||
|
@ -8693,7 +8693,8 @@ static int
|
|||||||
qemuDomainSnapshotCreateActive(virConnectPtr conn,
|
qemuDomainSnapshotCreateActive(virConnectPtr conn,
|
||||||
struct qemud_driver *driver,
|
struct qemud_driver *driver,
|
||||||
virDomainObjPtr *vmptr,
|
virDomainObjPtr *vmptr,
|
||||||
virDomainSnapshotObjPtr snap)
|
virDomainSnapshotObjPtr snap,
|
||||||
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
virDomainObjPtr vm = *vmptr;
|
virDomainObjPtr vm = *vmptr;
|
||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
@ -8723,6 +8724,24 @@ qemuDomainSnapshotCreateActive(virConnectPtr conn,
|
|||||||
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
||||||
ret = qemuMonitorCreateSnapshot(priv->mon, snap->def->name);
|
ret = qemuMonitorCreateSnapshot(priv->mon, snap->def->name);
|
||||||
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
||||||
|
if (ret < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
|
||||||
|
virDomainEventPtr event;
|
||||||
|
|
||||||
|
event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
|
||||||
|
VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
|
||||||
|
qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
|
||||||
|
virDomainAuditStop(vm, "from-snapshot");
|
||||||
|
/* We already filtered the _HALT flag for persistent domains
|
||||||
|
* only, so this end job never drops the last reference. */
|
||||||
|
ignore_value(qemuDomainObjEndJob(driver, vm));
|
||||||
|
resume = false;
|
||||||
|
vm = NULL;
|
||||||
|
if (event)
|
||||||
|
qemuDomainEventQueue(driver, event);
|
||||||
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (resume && virDomainObjIsActive(vm) &&
|
if (resume && virDomainObjIsActive(vm) &&
|
||||||
@ -8734,7 +8753,7 @@ cleanup:
|
|||||||
_("resuming after snapshot failed"));
|
_("resuming after snapshot failed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qemuDomainObjEndJob(driver, vm) == 0) {
|
if (vm && qemuDomainObjEndJob(driver, vm) == 0) {
|
||||||
/* Only possible if a transient vm quit while our locks were down,
|
/* Only possible if a transient vm quit while our locks were down,
|
||||||
* in which case we don't want to save snapshot metadata. */
|
* in which case we don't want to save snapshot metadata. */
|
||||||
*vmptr = NULL;
|
*vmptr = NULL;
|
||||||
@ -8761,7 +8780,8 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
|
|||||||
|
|
||||||
virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
|
virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
|
||||||
VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
|
VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
|
||||||
VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
|
VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
|
||||||
|
VIR_DOMAIN_SNAPSHOT_CREATE_HALT, NULL);
|
||||||
|
|
||||||
if (((flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) &&
|
if (((flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) &&
|
||||||
!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)) ||
|
!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)) ||
|
||||||
@ -8784,6 +8804,11 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
|
|||||||
"%s", _("domain is marked for auto destroy"));
|
"%s", _("domain is marked for auto destroy"));
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
|
||||||
|
qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
||||||
|
_("cannot halt after transient domain snapshot"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(def = virDomainSnapshotDefParseString(xmlDesc, driver->caps,
|
if (!(def = virDomainSnapshotDefParseString(xmlDesc, driver->caps,
|
||||||
QEMU_EXPECTED_VIRT_TYPES,
|
QEMU_EXPECTED_VIRT_TYPES,
|
||||||
@ -8924,7 +8949,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
} else {
|
} else {
|
||||||
if (qemuDomainSnapshotCreateActive(domain->conn, driver,
|
if (qemuDomainSnapshotCreateActive(domain->conn, driver,
|
||||||
&vm, snap) < 0)
|
&vm, snap, flags) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user