diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 88648659d6..c213919223 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2622,6 +2622,7 @@ int virDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, typedef enum { VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN = (1 << 0), /* Also delete children */ VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY = (1 << 1), /* Delete just metadata */ + VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY = (1 << 2), /* Delete just children */ } virDomainSnapshotDeleteFlags; int virDomainSnapshotDelete(virDomainSnapshotPtr snapshot, diff --git a/src/libvirt.c b/src/libvirt.c index 4d80e2fe2f..9b6d69303b 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -16057,16 +16057,22 @@ error: * * Delete the snapshot. * - * If @flags is 0, then just this snapshot is deleted, and changes from - * this snapshot are automatically merged into children snapshots. If - * @flags includes VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN, then this snapshot - * and any children snapshots are deleted. If @flags includes - * VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, then any snapshot metadata - * tracked by libvirt is removed while keeping the snapshot contents - * intact; if a hypervisor does not require any libvirt metadata to - * track snapshots, then this flag is silently ignored. + * If @flags is 0, then just this snapshot is deleted, and changes + * from this snapshot are automatically merged into children + * snapshots. If @flags includes VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN, + * then this snapshot and any descendant snapshots are deleted. If + * @flags includes VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, then any + * descendant snapshots are deleted, but this snapshot remains. These + * two flags are mutually exclusive. * - * Returns 0 if the snapshot was successfully deleted, -1 on error. + * If @flags includes VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, then + * any snapshot metadata tracked by libvirt is removed while keeping + * the snapshot contents intact; if a hypervisor does not require any + * libvirt metadata to track snapshots, then this flag is silently + * ignored. + * + * Returns 0 if the selected snapshot(s) were successfully deleted, + * -1 on error. */ int virDomainSnapshotDelete(virDomainSnapshotPtr snapshot, @@ -16091,6 +16097,14 @@ virDomainSnapshotDelete(virDomainSnapshotPtr snapshot, goto error; } + if ((flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN) && + (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) { + virLibDomainError(VIR_ERR_INVALID_ARG, + _("children and children_only flags are " + "mutually exclusive")); + goto error; + } + if (conn->driver->domainSnapshotDelete) { int ret = conn->driver->domainSnapshotDelete(snapshot, flags); if (ret < 0) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 7028d72850..1bb83cd129 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -9512,7 +9512,8 @@ static int qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot, bool metadata_only = !!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY); virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN | - VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1); + VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY | + VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1); qemuDriverLock(driver); virUUIDFormat(snapshot->domain->uuid, uuidstr); @@ -9534,7 +9535,8 @@ static int qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot, if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0) goto cleanup; - if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN) { + if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN | + VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) { rem.driver = driver; rem.vm = vm; rem.metadata_only = metadata_only; @@ -9546,8 +9548,20 @@ static int qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot, &rem); if (rem.err < 0) goto endjob; - if (rem.current) + if (rem.current) { + if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) { + snap->def->current = true; + if (qemuDomainSnapshotWriteMetadata(vm, snap, + driver->snapshotDir) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to set snapshot '%s' as current"), + snap->def->name); + snap->def->current = false; + goto endjob; + } + } vm->current_snapshot = snap; + } } else { rep.driver = driver; rep.parent = snap->def->parent; @@ -9560,7 +9574,10 @@ static int qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot, goto endjob; } - ret = qemuDomainSnapshotDiscard(driver, vm, snap, true, metadata_only); + if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) + ret = 0; + else + ret = qemuDomainSnapshotDiscard(driver, vm, snap, true, metadata_only); endjob: if (qemuDomainObjEndJob(driver, vm) == 0)