]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
snapshot: Don't hose list on deletion failure
authorEric Blake <eblake@redhat.com>
Thu, 18 Oct 2018 00:24:34 +0000 (19:24 -0500)
committerEric Blake <eblake@redhat.com>
Thu, 8 Nov 2018 13:19:27 +0000 (07:19 -0600)
If qemuDomainSnapshotDiscard() fails for any reason (rare,
but possible with an ill-timed ENOMEM or if
qemuDomainSnapshotForEachQcow2() has problems talking to the
qemu guest monitor), then an attempt to retry the snapshot
deletion API will crash because we didn't undo the effects
of virDomainSnapshotDropParent() temporarily rearranging the
internal list structures, and the second attempt to drop
parents will dereference NULL.  Fix it by instead noting that
there are only two callers to qemuDomainSnapshotDiscard(),
and only one of the two callers wants the parent to be updated;
thus we can move the call to virDomainSnapshotDropParent()
into a code path that only gets executed on success.

Signed-off-by: Eric Blake <eblake@redhat.com>
ACKed-by: Michal Privoznik <mprivozn@redhat.com>
src/qemu/qemu_domain.c
src/qemu/qemu_driver.c

index 045a7b4ac0a1374d6ff7a950827be186cd005bda..e25afdad6bb27526e488c8e986d4bc8ca5485faf 100644 (file)
@@ -8249,7 +8249,7 @@ int
 qemuDomainSnapshotDiscard(virQEMUDriverPtr driver,
                           virDomainObjPtr vm,
                           virDomainSnapshotObjPtr snap,
-                          bool update_current,
+                          bool update_parent,
                           bool metadata_only)
 {
     char *snapFile = NULL;
@@ -8278,7 +8278,7 @@ qemuDomainSnapshotDiscard(virQEMUDriverPtr driver,
         goto cleanup;
 
     if (snap == vm->current_snapshot) {
-        if (update_current && snap->def->parent) {
+        if (update_parent && snap->def->parent) {
             parentsnap = virDomainSnapshotFindByName(vm->snapshots,
                                                      snap->def->parent);
             if (!parentsnap) {
@@ -8301,6 +8301,8 @@ qemuDomainSnapshotDiscard(virQEMUDriverPtr driver,
 
     if (unlink(snapFile) < 0)
         VIR_WARN("Failed to unlink %s", snapFile);
+    if (update_parent)
+        virDomainSnapshotDropParent(snap);
     virDomainSnapshotObjListRemove(vm->snapshots, snap);
 
     ret = 0;
index a52e2495d51da73a3ff0678432b1982c2703a3d3..9f71641dfa133df339157b10958cf5c18c0baa3b 100644 (file)
@@ -16526,7 +16526,6 @@ qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
         snap->first_child = NULL;
         ret = 0;
     } else {
-        virDomainSnapshotDropParent(snap);
         ret = qemuDomainSnapshotDiscard(driver, vm, snap, true, metadata_only);
     }