From 709b0f37c5cb22b8846e59c2259ea30e73d72d92 Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Thu, 3 Jan 2013 14:20:09 +0100 Subject: [PATCH] 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. --- src/qemu/qemu_driver.c | 51 +++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 15 deletions(-) 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;