Maintain the parent/child relationships of all qemu snapshots.
* src/qemu/qemu_driver.c (qemuDomainSnapshotLoad): Populate
relationships after loading.
(qemuDomainSnapshotCreateXML): Set relations on creation; tweak
redefinition to reuse existing object.
(qemuDomainSnapshotReparentChildren, qemuDomainSnapshotDelete):
Clear relations on delete.
---
src/qemu/qemu_driver.c | 72 ++++++++++++++++++++++++++++++++++++++---------
1 files changed, 58 insertions(+), 14 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 5db67b8..501a3fc 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -376,6 +376,10 @@ static void qemuDomainSnapshotLoad(void *payload,
vm->current_snapshot = NULL;
}
+ if (virDomainSnapshotUpdateRelations(&vm->snapshots) < 0)
+ VIR_ERROR(_("Snapshots have inconsistent relations for domain %s"),
+ vm->def->name);
+
/* FIXME: qemu keeps internal track of snapshots. We can get access
* to this info via the "info snapshots" monitor command for running
* domains, or via "qemu-img snapshot -l" for shutoff domains. It would
@@ -9148,6 +9152,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
virDomainSnapshotDefPtr def = NULL;
bool update_current = true;
unsigned int parse_flags = 0;
+ virDomainSnapshotObjPtr other = NULL;
virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
@@ -9190,8 +9195,6 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
goto cleanup;
if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
- virDomainSnapshotObjPtr other = NULL;
-
/* Prevent circular chains */
if (def->parent) {
if (STREQ(def->name, def->parent)) {
@@ -9267,7 +9270,12 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
update_current = true;
vm->current_snapshot = NULL;
}
- virDomainSnapshotObjListRemove(&vm->snapshots, other);
+ /* Drop and rebuild the parent relationship, but keep all
+ * child relations by reusing snap. */
+ virDomainSnapshotDropParent(&vm->snapshots, other);
+ virDomainSnapshotDefFree(other->def);
+ other->def = NULL;
+ snap = other;
}
if (def->state == VIR_DOMAIN_DISK_SNAPSHOT && def->dom) {
if (virDomainSnapshotAlignDisks(def,
@@ -9309,7 +9317,9 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
}
}
- if (!(snap = virDomainSnapshotAssignDef(&vm->snapshots, def)))
+ if (snap)
+ snap->def = def;
+ else if (!(snap = virDomainSnapshotAssignDef(&vm->snapshots, def)))
goto cleanup;
def = NULL;
@@ -9366,11 +9376,25 @@ cleanup:
if (vm) {
if (snapshot && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
if (qemuDomainSnapshotWriteMetadata(vm, snap,
- driver->snapshotDir) < 0)
+ driver->snapshotDir) < 0) {
VIR_WARN("unable to save metadata for snapshot %s",
snap->def->name);
- else if (update_current)
- vm->current_snapshot = snap;
+ } else {
+ if (update_current)
+ vm->current_snapshot = snap;
+ if (snap->def->parent) {
+ other = virDomainSnapshotFindByName(&vm->snapshots,
+ snap->def->parent);
+ snap->parent = other;
+ other->nchildren++;
+ snap->sibling = other->first_child;
+ other->first_child = snap;
+ } else {
+ vm->snapshots.nroots++;
+ snap->sibling = vm->snapshots.first_root;
+ vm->snapshots.first_root = snap;
+ }
+ }
} else if (snap) {
virDomainSnapshotObjListRemove(&vm->snapshots, snap);
}
@@ -10062,9 +10086,10 @@ cleanup:
struct snap_reparent {
struct qemud_driver *driver;
- const char *parent;
+ virDomainSnapshotObjPtr parent;
virDomainObjPtr vm;
int err;
+ virDomainSnapshotObjPtr last;
};
static void
@@ -10080,9 +10105,10 @@ qemuDomainSnapshotReparentChildren(void *payload,
}
VIR_FREE(snap->def->parent);
+ snap->parent = rep->parent;
- if (rep->parent != NULL) {
- snap->def->parent = strdup(rep->parent);
+ if (rep->parent) {
+ snap->def->parent = strdup(rep->parent->def->name);
if (snap->def->parent == NULL) {
virReportOOMError();
@@ -10091,6 +10117,9 @@ qemuDomainSnapshotReparentChildren(void *payload,
}
}
+ if (!snap->sibling)
+ rep->last = snap;
+
rep->err = qemuDomainSnapshotWriteMetadata(rep->vm, snap,
rep->driver->snapshotDir);
}
@@ -10175,22 +10204,37 @@ static int qemuDomainSnapshotDelete(virDomainSnapshotPtr
snapshot,
}
vm->current_snapshot = snap;
}
- } else {
+ } else if (snap->nchildren) {
rep.driver = driver;
- rep.parent = snap->def->parent;
+ rep.parent = snap->parent;
rep.vm = vm;
rep.err = 0;
+ rep.last = NULL;
virDomainSnapshotForEachChild(&vm->snapshots, snap,
qemuDomainSnapshotReparentChildren,
&rep);
if (rep.err < 0)
goto endjob;
+ /* Can't modify siblings during ForEachChild, so do it now. */
+ if (snap->parent) {
+ snap->parent->nchildren += snap->nchildren;
+ rep.last->sibling = snap->parent->first_child;
+ snap->parent->first_child = snap->first_child;
+ } else {
+ vm->snapshots.nroots += snap->nchildren;
+ rep.last->sibling = vm->snapshots.first_root;
+ vm->snapshots.first_root = snap->first_child;
+ }
}
- if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)
+ if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
+ snap->nchildren = 0;
+ snap->first_child = NULL;
ret = 0;
- else
+ } else {
+ virDomainSnapshotDropParent(&vm->snapshots, snap);
ret = qemuDomainSnapshotDiscard(driver, vm, snap, true, metadata_only);
+ }
endjob:
if (qemuDomainObjEndJob(driver, vm) == 0)
--
1.7.4.4