virDomainSnapshotFindByName(list, NULL) should return NULL, rather
than the internal-use-only metaroot. Most existing callers pass in a
non-NULL name; the few that don't are immediately calling
virDomainMomentSetParent (which indeed needs the metaroot if the
parent name is NULL); but as the leak is ugly, it is worth instead
making virDomainMomentSetParent static and adding a new function for
resolving the link of a brand new moment within its list (and where we
are either requesting NULL for a new root moment, or requesting the
name of the current moment, and therefore the new function does not
need to return failure, but merely warn if future code breaks our
assumptions).
Missed when commit 02c4e24d refactored things to attempt to remove
direct metaroot manipulations out of the qemu and test drivers into
internal-only details, and made more obvious when commit dc8d3dc6
factored it out into a separate file.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
src/conf/virdomainmomentobjlist.h | 4 ++--
src/conf/virdomainsnapshotobjlist.h | 2 ++
src/conf/virdomainmomentobjlist.c | 34 +++++++++++++++++++++++++----
src/conf/virdomainsnapshotobjlist.c | 9 ++++++++
src/libvirt_private.syms | 2 +-
src/qemu/qemu_driver.c | 5 +----
src/test/test_driver.c | 5 +----
7 files changed, 46 insertions(+), 15 deletions(-)
diff --git a/src/conf/virdomainmomentobjlist.h b/src/conf/virdomainmomentobjlist.h
index 4067e928f4..897d8d54d1 100644
--- a/src/conf/virdomainmomentobjlist.h
+++ b/src/conf/virdomainmomentobjlist.h
@@ -60,8 +60,8 @@ void virDomainMomentDropParent(virDomainMomentObjPtr moment);
void virDomainMomentDropChildren(virDomainMomentObjPtr moment);
void virDomainMomentMoveChildren(virDomainMomentObjPtr from,
virDomainMomentObjPtr to);
-void virDomainMomentSetParent(virDomainMomentObjPtr moment,
- virDomainMomentObjPtr parent);
+void virDomainMomentLinkParent(virDomainMomentObjListPtr moments,
+ virDomainMomentObjPtr moment);
virDomainMomentObjListPtr virDomainMomentObjListNew(void);
void virDomainMomentObjListFree(virDomainMomentObjListPtr moments);
diff --git a/src/conf/virdomainsnapshotobjlist.h b/src/conf/virdomainsnapshotobjlist.h
index fed8d22bc8..b8c80b39ed 100644
--- a/src/conf/virdomainsnapshotobjlist.h
+++ b/src/conf/virdomainsnapshotobjlist.h
@@ -51,6 +51,8 @@ void virDomainSnapshotObjListRemoveAll(virDomainSnapshotObjListPtr
snapshots);
int virDomainSnapshotForEach(virDomainSnapshotObjListPtr snapshots,
virHashIterator iter,
void *data);
+void virDomainSnapshotLinkParent(virDomainSnapshotObjListPtr snapshots,
+ virDomainMomentObjPtr moment);
int virDomainSnapshotUpdateRelations(virDomainSnapshotObjListPtr snapshots);
int virDomainSnapshotCheckCycles(virDomainSnapshotObjListPtr snapshots,
virDomainSnapshotDefPtr def,
diff --git a/src/conf/virdomainmomentobjlist.c b/src/conf/virdomainmomentobjlist.c
index 7cb1745525..5c147bdbbf 100644
--- a/src/conf/virdomainmomentobjlist.c
+++ b/src/conf/virdomainmomentobjlist.c
@@ -151,7 +151,7 @@ virDomainMomentDropChildren(virDomainMomentObjPtr moment)
/* Add @moment to @parent's list of children. */
-void
+static void
virDomainMomentSetParent(virDomainMomentObjPtr moment,
virDomainMomentObjPtr parent)
{
@@ -162,6 +162,27 @@ virDomainMomentSetParent(virDomainMomentObjPtr moment,
}
+/* Add @moment to the appropriate parent's list of children. The
+ * caller must ensure that moment->def->parent_name is either NULL
+ * (for a new root) or set to an existing moment already in the
+ * list. */
+void
+virDomainMomentLinkParent(virDomainMomentObjListPtr moments,
+ virDomainMomentObjPtr moment)
+{
+ virDomainMomentObjPtr parent;
+
+ parent = virDomainMomentFindByName(moments, moment->def->parent_name);
+ if (!parent) {
+ parent = &moments->metaroot;
+ if (moment->def->parent_name)
+ VIR_WARN("moment %s lacks parent %s", moment->def->name,
+ moment->def->parent_name);
+ }
+ virDomainMomentSetParent(moment, parent);
+}
+
+
/* Take all children of @from and convert them into children of @to. */
void
virDomainMomentMoveChildren(virDomainMomentObjPtr from,
@@ -390,7 +411,9 @@ virDomainMomentObjPtr
virDomainMomentFindByName(virDomainMomentObjListPtr moments,
const char *name)
{
- return name ? virHashLookup(moments->objs, name) : &moments->metaroot;
+ if (name)
+ return virHashLookup(moments->objs, name);
+ return NULL;
}
@@ -484,9 +507,12 @@ virDomainMomentSetRelations(void *payload,
parent = virDomainMomentFindByName(curr->moments, obj->def->parent_name);
if (!parent) {
- curr->err = -1;
parent = &curr->moments->metaroot;
- VIR_WARN("moment %s lacks parent", obj->def->name);
+ if (obj->def->parent_name) {
+ curr->err = -1;
+ VIR_WARN("moment %s lacks parent %s", obj->def->name,
+ obj->def->parent_name);
+ }
} else {
tmp = parent;
while (tmp && tmp->def) {
diff --git a/src/conf/virdomainsnapshotobjlist.c b/src/conf/virdomainsnapshotobjlist.c
index 99bc4bb0c5..95622f0ba7 100644
--- a/src/conf/virdomainsnapshotobjlist.c
+++ b/src/conf/virdomainsnapshotobjlist.c
@@ -223,6 +223,15 @@ virDomainSnapshotForEach(virDomainSnapshotObjListPtr snapshots,
}
+/* Populate parent link of a given snapshot. */
+void
+virDomainSnapshotLinkParent(virDomainSnapshotObjListPtr snapshots,
+ virDomainMomentObjPtr snap)
+{
+ return virDomainMomentLinkParent(snapshots->base, snap);
+}
+
+
/* Populate parent link and child count of all snapshots, with all
* assigned defs having relations starting as 0/NULL. Return 0 on
* success, -1 if a parent is missing or if a circular relationship
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index dff97bd82a..ff5a77b0e2 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -978,7 +978,6 @@ virDomainMomentDropParent;
virDomainMomentForEachChild;
virDomainMomentForEachDescendant;
virDomainMomentMoveChildren;
-virDomainMomentSetParent;
# conf/virdomainobjlist.h
@@ -1007,6 +1006,7 @@ virDomainSnapshotFindByName;
virDomainSnapshotForEach;
virDomainSnapshotGetCurrent;
virDomainSnapshotGetCurrentName;
+virDomainSnapshotLinkParent;
virDomainSnapshotObjListFree;
virDomainSnapshotObjListGetNames;
virDomainSnapshotObjListNew;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 482f915b67..065e0a1bd8 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -15540,7 +15540,6 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
bool update_current = true;
bool redefine = flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE;
unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
- virDomainMomentObjPtr other = NULL;
int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
bool align_match = true;
virQEMUDriverConfigPtr cfg = NULL;
@@ -15807,9 +15806,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
snap->def->name);
virDomainSnapshotObjListRemove(vm->snapshots, snap);
} else {
- other = virDomainSnapshotFindByName(vm->snapshots,
- snap->def->parent_name);
- virDomainMomentSetParent(snap, other);
+ virDomainSnapshotLinkParent(vm->snapshots, snap);
}
} else if (snap) {
virDomainSnapshotObjListRemove(vm->snapshots, snap);
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index 2e33a9dd55..d96dd638e7 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -7361,12 +7361,9 @@ testDomainSnapshotCreateXML(virDomainPtr domain,
cleanup:
if (vm) {
if (snapshot) {
- virDomainMomentObjPtr other;
if (update_current)
virDomainSnapshotSetCurrent(vm->snapshots, snap);
- other = virDomainSnapshotFindByName(vm->snapshots,
- snap->def->parent_name);
- virDomainMomentSetParent(snap, other);
+ virDomainSnapshotLinkParent(vm->snapshots, snap);
}
virDomainObjEndAPI(&vm);
}
--
2.20.1