From: Peter Krempa Date: Thu, 3 Jan 2013 13:20:09 +0000 (+0100) Subject: snapshot: qemu: Fix segfault and vanishing snapshots when redefining X-Git-Tag: v1.0.2-rc1~287 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=709b0f37c5cb22b8846e59c2259ea30e73d72d92;p=thirdparty%2Flibvirt.git snapshot: qemu: Fix segfault and vanishing snapshots when redefining When the disk alignment check done while redefining an existing snapshot failed, the qemu driver attempted to free the existing snapshot. As in the cleanup path the definition of the snapshot wasn't assigned, the cleanup code dereferenced a NULL pointer. This patch changes the behavior on error paths while redefining snapshot in two ways: 1) On failure, modifications done on the snapshot definition object are rolled back. 2) The previous definition of the data isn't freed until it's certain it won't be needed any more. This change avoids the segfault and additionally the snapshot doesn't vanish if redefinition fails for some reason. --- diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index c045d3d7cb..92476bd57b 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -11408,6 +11408,24 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain, } } + if (def->dom) { + if (def->state == VIR_DOMAIN_DISK_SNAPSHOT || + def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) { + align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL; + align_match = false; + } + + if (virDomainSnapshotAlignDisks(def, align_location, + align_match) < 0) { + /* revert stealing of the snapshot domain definition */ + if (def->dom && !other->def->dom) { + other->def->dom = def->dom; + def->dom = NULL; + } + goto cleanup; + } + } + if (other == vm->current_snapshot) { update_current = true; vm->current_snapshot = NULL; @@ -11417,18 +11435,20 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain, * child relations by reusing snap. */ virDomainSnapshotDropParent(other); virDomainSnapshotDefFree(other->def); - other->def = NULL; + other->def = def; + def = NULL; snap = other; - } - if (def->dom) { - if (def->state == VIR_DOMAIN_DISK_SNAPSHOT || - def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) { - align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL; - align_match = false; + } else { + if (def->dom) { + if (def->state == VIR_DOMAIN_DISK_SNAPSHOT || + def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) { + align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL; + align_match = false; + } + if (virDomainSnapshotAlignDisks(def, align_location, + align_match) < 0) + goto cleanup; } - if (virDomainSnapshotAlignDisks(def, align_location, - align_match) < 0) - goto cleanup; } } else { /* Easiest way to clone inactive portion of vm->def is via @@ -11463,11 +11483,12 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain, goto cleanup; } - if (snap) - snap->def = def; - else if (!(snap = virDomainSnapshotAssignDef(vm->snapshots, def))) - goto cleanup; - def = NULL; + if (!snap) { + if (!(snap = virDomainSnapshotAssignDef(vm->snapshots, def))) + goto cleanup; + + def = NULL; + } if (update_current) snap->def->current = true;