diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index c213919223..0f0efc1a4e 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2567,6 +2567,8 @@ typedef enum { snapshot current */ VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA = (1 << 2), /* Make snapshot without remembering it */ + VIR_DOMAIN_SNAPSHOT_CREATE_HALT = (1 << 3), /* Stop running guest + after snapshot */ } virDomainSnapshotCreateFlags; /* Take a snapshot of the current VM state */ diff --git a/src/libvirt.c b/src/libvirt.c index 9b6d69303b..b29779ef7d 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -15637,6 +15637,12 @@ error: * the just-created snapshot has its metadata deleted. This flag is * 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. */ virDomainSnapshotPtr @@ -15680,6 +15686,12 @@ virDomainSnapshotCreateXML(virDomainPtr domain, _("redefine and no metadata flags are mutually exclusive")); 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) { virDomainSnapshotPtr ret; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 1bb83cd129..843a4971da 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -8693,7 +8693,8 @@ static int qemuDomainSnapshotCreateActive(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr *vmptr, - virDomainSnapshotObjPtr snap) + virDomainSnapshotObjPtr snap, + unsigned int flags) { virDomainObjPtr vm = *vmptr; qemuDomainObjPrivatePtr priv = vm->privateData; @@ -8723,6 +8724,24 @@ qemuDomainSnapshotCreateActive(virConnectPtr conn, qemuDomainObjEnterMonitorWithDriver(driver, vm); ret = qemuMonitorCreateSnapshot(priv->mon, snap->def->name); 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: if (resume && virDomainObjIsActive(vm) && @@ -8734,7 +8753,7 @@ cleanup: _("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, * in which case we don't want to save snapshot metadata. */ *vmptr = NULL; @@ -8761,7 +8780,8 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain, virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE | 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) && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)) || @@ -8784,6 +8804,11 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain, "%s", _("domain is marked for auto destroy")); 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, QEMU_EXPECTED_VIRT_TYPES, @@ -8924,7 +8949,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain, goto cleanup; } else { if (qemuDomainSnapshotCreateActive(domain->conn, driver, - &vm, snap) < 0) + &vm, snap, flags) < 0) goto cleanup; }