snapshot: Track current snapshot in virDomainSnapshotObjList

It is easier to track the current snapshot as part of the list of
snapshots. In particular, doing so lets us guarantee that the current
snapshot is cleared if that snapshot is removed from the list (rather
than depending on the caller to do so, and risking a use-after-free
problem, such as the one recently patched in 1db9d0efbf).  This
requires the addition of several new accessor functions, as well as a
useful return type for virDomainSnapshotObjListRemove().  A few error
handling sites that were previously setting vm->current_snapshot =
NULL can now be dropped, because the previous function call has now
done it already.  Also, qemuDomainRevertToSnapshot() was setting the
current vm twice, so keep only the one used on the success path.

Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: John Ferlan <jferlan@redhat.com>
This commit is contained in:
Eric Blake 2019-03-21 15:00:08 -05:00
parent 40bc98ddaf
commit 4819f54bd3
8 changed files with 107 additions and 65 deletions

View File

@ -2517,7 +2517,6 @@ struct _virDomainObj {
virDomainDefPtr newDef; /* New definition to activate at shutdown */ virDomainDefPtr newDef; /* New definition to activate at shutdown */
virDomainSnapshotObjListPtr snapshots; virDomainSnapshotObjListPtr snapshots;
virDomainSnapshotObjPtr current_snapshot;
bool hasManagedSave; bool hasManagedSave;

View File

@ -974,9 +974,9 @@ virDomainSnapshotRedefinePrep(virDomainPtr domain,
return -1; return -1;
} }
if (other) { if (other) {
if (other == vm->current_snapshot) { if (other == virDomainSnapshotGetCurrent(vm->snapshots)) {
*update_current = true; *update_current = true;
vm->current_snapshot = NULL; virDomainSnapshotSetCurrent(vm->snapshots, NULL);
} }
/* Drop and rebuild the parent relationship, but keep all /* Drop and rebuild the parent relationship, but keep all

View File

@ -40,6 +40,7 @@ struct _virDomainSnapshotObjList {
virHashTable *objs; virHashTable *objs;
virDomainSnapshotObj metaroot; /* Special parent of all root snapshots */ virDomainSnapshotObj metaroot; /* Special parent of all root snapshots */
virDomainSnapshotObjPtr current; /* The current snapshot, if any */
}; };
@ -52,7 +53,6 @@ int
virDomainSnapshotObjListParse(const char *xmlStr, virDomainSnapshotObjListParse(const char *xmlStr,
const unsigned char *domain_uuid, const unsigned char *domain_uuid,
virDomainSnapshotObjListPtr snapshots, virDomainSnapshotObjListPtr snapshots,
virDomainSnapshotObjPtr *current_snap,
virCapsPtr caps, virCapsPtr caps,
virDomainXMLOptionPtr xmlopt, virDomainXMLOptionPtr xmlopt,
unsigned int flags) unsigned int flags)
@ -64,6 +64,7 @@ virDomainSnapshotObjListParse(const char *xmlStr,
int n; int n;
size_t i; size_t i;
int keepBlanksDefault = xmlKeepBlanksDefault(0); int keepBlanksDefault = xmlKeepBlanksDefault(0);
virDomainSnapshotObjPtr snap;
VIR_AUTOFREE(xmlNodePtr *) nodes = NULL; VIR_AUTOFREE(xmlNodePtr *) nodes = NULL;
VIR_AUTOFREE(char *) current = NULL; VIR_AUTOFREE(char *) current = NULL;
@ -73,7 +74,7 @@ virDomainSnapshotObjListParse(const char *xmlStr,
_("incorrect flags for bulk parse")); _("incorrect flags for bulk parse"));
return -1; return -1;
} }
if (snapshots->metaroot.nchildren || *current_snap) { if (snapshots->metaroot.nchildren || snapshots->current) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("bulk define of snapshots only possible with " _("bulk define of snapshots only possible with "
"no existing snapshot")); "no existing snapshot"));
@ -103,7 +104,6 @@ virDomainSnapshotObjListParse(const char *xmlStr,
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
virDomainSnapshotDefPtr def; virDomainSnapshotDefPtr def;
virDomainSnapshotObjPtr snap;
def = virDomainSnapshotDefParseNode(xml, nodes[i], caps, xmlopt, NULL, def = virDomainSnapshotDefParseNode(xml, nodes[i], caps, xmlopt, NULL,
flags); flags);
@ -126,12 +126,13 @@ virDomainSnapshotObjListParse(const char *xmlStr,
} }
if (current) { if (current) {
if (!(*current_snap = virDomainSnapshotFindByName(snapshots, snap = virDomainSnapshotFindByName(snapshots, current);
current))) { if (!snap) {
virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
_("no snapshot matching current='%s'"), current); _("no snapshot matching current='%s'"), current);
goto cleanup; goto cleanup;
} }
virDomainSnapshotSetCurrent(snapshots, snap);
} }
ret = n; ret = n;
@ -181,7 +182,6 @@ int
virDomainSnapshotObjListFormat(virBufferPtr buf, virDomainSnapshotObjListFormat(virBufferPtr buf,
const char *uuidstr, const char *uuidstr,
virDomainSnapshotObjListPtr snapshots, virDomainSnapshotObjListPtr snapshots,
virDomainSnapshotObjPtr current_snapshot,
virCapsPtr caps, virCapsPtr caps,
virDomainXMLOptionPtr xmlopt, virDomainXMLOptionPtr xmlopt,
unsigned int flags) unsigned int flags)
@ -196,9 +196,8 @@ virDomainSnapshotObjListFormat(virBufferPtr buf,
virCheckFlags(VIR_DOMAIN_SNAPSHOT_FORMAT_SECURE, -1); virCheckFlags(VIR_DOMAIN_SNAPSHOT_FORMAT_SECURE, -1);
virBufferAddLit(buf, "<snapshots"); virBufferAddLit(buf, "<snapshots");
if (current_snapshot) virBufferEscapeString(buf, " current='%s'",
virBufferEscapeString(buf, " current='%s'", virDomainSnapshotGetCurrentName(snapshots));
current_snapshot->def->name);
virBufferAddLit(buf, ">\n"); virBufferAddLit(buf, ">\n");
virBufferAdjustIndent(buf, 2); virBufferAdjustIndent(buf, 2);
if (virDomainSnapshotForEach(snapshots, virDomainSnapshotFormatOne, if (virDomainSnapshotForEach(snapshots, virDomainSnapshotFormatOne,
@ -436,10 +435,53 @@ virDomainSnapshotFindByName(virDomainSnapshotObjListPtr snapshots,
return name ? virHashLookup(snapshots->objs, name) : &snapshots->metaroot; return name ? virHashLookup(snapshots->objs, name) : &snapshots->metaroot;
} }
void virDomainSnapshotObjListRemove(virDomainSnapshotObjListPtr snapshots,
virDomainSnapshotObjPtr snapshot) /* Return the current snapshot, or NULL */
virDomainSnapshotObjPtr
virDomainSnapshotGetCurrent(virDomainSnapshotObjListPtr snapshots)
{ {
return snapshots->current;
}
/* Return the current snapshot's name, or NULL */
const char *
virDomainSnapshotGetCurrentName(virDomainSnapshotObjListPtr snapshots)
{
if (snapshots->current)
return snapshots->current->def->name;
return NULL;
}
/* Return true if name matches the current snapshot */
bool
virDomainSnapshotIsCurrentName(virDomainSnapshotObjListPtr snapshots,
const char *name)
{
return snapshots->current && STREQ(snapshots->current->def->name, name);
}
/* Update the current snapshot, using NULL if no current remains */
void
virDomainSnapshotSetCurrent(virDomainSnapshotObjListPtr snapshots,
virDomainSnapshotObjPtr snapshot)
{
snapshots->current = snapshot;
}
/* Remove snapshot from the list; return true if it was current */
bool
virDomainSnapshotObjListRemove(virDomainSnapshotObjListPtr snapshots,
virDomainSnapshotObjPtr snapshot)
{
bool ret = snapshots->current == snapshot;
virHashRemoveEntry(snapshots->objs, snapshot->def->name); virHashRemoveEntry(snapshots->objs, snapshot->def->name);
if (ret)
snapshots->current = NULL;
return ret;
} }
int int
@ -506,6 +548,8 @@ virDomainSnapshotUpdateRelations(virDomainSnapshotObjListPtr snapshots)
snapshots->metaroot.nchildren = 0; snapshots->metaroot.nchildren = 0;
snapshots->metaroot.first_child = NULL; snapshots->metaroot.first_child = NULL;
virHashForEach(snapshots->objs, virDomainSnapshotSetRelations, &act); virHashForEach(snapshots->objs, virDomainSnapshotSetRelations, &act);
if (act.err)
snapshots->current = NULL;
return act.err; return act.err;
} }

View File

@ -33,14 +33,12 @@ void virDomainSnapshotObjListFree(virDomainSnapshotObjListPtr snapshots);
int virDomainSnapshotObjListParse(const char *xmlStr, int virDomainSnapshotObjListParse(const char *xmlStr,
const unsigned char *domain_uuid, const unsigned char *domain_uuid,
virDomainSnapshotObjListPtr snapshots, virDomainSnapshotObjListPtr snapshots,
virDomainSnapshotObjPtr *current_snap,
virCapsPtr caps, virCapsPtr caps,
virDomainXMLOptionPtr xmlopt, virDomainXMLOptionPtr xmlopt,
unsigned int flags); unsigned int flags);
int virDomainSnapshotObjListFormat(virBufferPtr buf, int virDomainSnapshotObjListFormat(virBufferPtr buf,
const char *uuidstr, const char *uuidstr,
virDomainSnapshotObjListPtr snapshots, virDomainSnapshotObjListPtr snapshots,
virDomainSnapshotObjPtr current_snapshot,
virCapsPtr caps, virCapsPtr caps,
virDomainXMLOptionPtr xmlopt, virDomainXMLOptionPtr xmlopt,
unsigned int flags); unsigned int flags);
@ -57,7 +55,13 @@ int virDomainSnapshotObjListNum(virDomainSnapshotObjListPtr snapshots,
unsigned int flags); unsigned int flags);
virDomainSnapshotObjPtr virDomainSnapshotFindByName(virDomainSnapshotObjListPtr snapshots, virDomainSnapshotObjPtr virDomainSnapshotFindByName(virDomainSnapshotObjListPtr snapshots,
const char *name); const char *name);
void virDomainSnapshotObjListRemove(virDomainSnapshotObjListPtr snapshots, virDomainSnapshotObjPtr virDomainSnapshotGetCurrent(virDomainSnapshotObjListPtr snapshots);
const char *virDomainSnapshotGetCurrentName(virDomainSnapshotObjListPtr snapshots);
bool virDomainSnapshotIsCurrentName(virDomainSnapshotObjListPtr snapshots,
const char *name);
void virDomainSnapshotSetCurrent(virDomainSnapshotObjListPtr snapshots,
virDomainSnapshotObjPtr snapshot);
bool virDomainSnapshotObjListRemove(virDomainSnapshotObjListPtr snapshots,
virDomainSnapshotObjPtr snapshot); virDomainSnapshotObjPtr snapshot);
int virDomainSnapshotForEach(virDomainSnapshotObjListPtr snapshots, int virDomainSnapshotForEach(virDomainSnapshotObjListPtr snapshots,
virHashIterator iter, virHashIterator iter,

View File

@ -990,6 +990,9 @@ virDomainListSnapshots;
virDomainSnapshotAssignDef; virDomainSnapshotAssignDef;
virDomainSnapshotFindByName; virDomainSnapshotFindByName;
virDomainSnapshotForEach; virDomainSnapshotForEach;
virDomainSnapshotGetCurrent;
virDomainSnapshotGetCurrentName;
virDomainSnapshotIsCurrentName;
virDomainSnapshotObjListFormat; virDomainSnapshotObjListFormat;
virDomainSnapshotObjListFree; virDomainSnapshotObjListFree;
virDomainSnapshotObjListGetNames; virDomainSnapshotObjListGetNames;
@ -997,6 +1000,7 @@ virDomainSnapshotObjListNew;
virDomainSnapshotObjListNum; virDomainSnapshotObjListNum;
virDomainSnapshotObjListParse; virDomainSnapshotObjListParse;
virDomainSnapshotObjListRemove; virDomainSnapshotObjListRemove;
virDomainSnapshotSetCurrent;
virDomainSnapshotUpdateRelations; virDomainSnapshotUpdateRelations;

View File

@ -8461,7 +8461,7 @@ qemuDomainSnapshotWriteMetadata(virDomainObjPtr vm,
unsigned int flags = VIR_DOMAIN_SNAPSHOT_FORMAT_SECURE | unsigned int flags = VIR_DOMAIN_SNAPSHOT_FORMAT_SECURE |
VIR_DOMAIN_SNAPSHOT_FORMAT_INTERNAL; VIR_DOMAIN_SNAPSHOT_FORMAT_INTERNAL;
if (vm->current_snapshot == snapshot) if (virDomainSnapshotGetCurrent(vm->snapshots) == snapshot)
flags |= VIR_DOMAIN_SNAPSHOT_FORMAT_CURRENT; flags |= VIR_DOMAIN_SNAPSHOT_FORMAT_CURRENT;
virUUIDFormat(vm->def->uuid, uuidstr); virUUIDFormat(vm->def->uuid, uuidstr);
newxml = virDomainSnapshotDefFormat(uuidstr, snapshot->def, caps, xmlopt, newxml = virDomainSnapshotDefFormat(uuidstr, snapshot->def, caps, xmlopt,
@ -8614,8 +8614,8 @@ qemuDomainSnapshotDiscard(virQEMUDriverPtr driver,
vm->def->name, snap->def->name) < 0) vm->def->name, snap->def->name) < 0)
goto cleanup; goto cleanup;
if (snap == vm->current_snapshot) { if (snap == virDomainSnapshotGetCurrent(vm->snapshots)) {
vm->current_snapshot = NULL; virDomainSnapshotSetCurrent(vm->snapshots, NULL);
if (update_parent && snap->def->parent) { if (update_parent && snap->def->parent) {
parentsnap = virDomainSnapshotFindByName(vm->snapshots, parentsnap = virDomainSnapshotFindByName(vm->snapshots,
snap->def->parent); snap->def->parent);
@ -8623,13 +8623,13 @@ qemuDomainSnapshotDiscard(virQEMUDriverPtr driver,
VIR_WARN("missing parent snapshot matching name '%s'", VIR_WARN("missing parent snapshot matching name '%s'",
snap->def->parent); snap->def->parent);
} else { } else {
vm->current_snapshot = parentsnap; virDomainSnapshotSetCurrent(vm->snapshots, parentsnap);
if (qemuDomainSnapshotWriteMetadata(vm, parentsnap, driver->caps, if (qemuDomainSnapshotWriteMetadata(vm, parentsnap, driver->caps,
driver->xmlopt, driver->xmlopt,
cfg->snapshotDir) < 0) { cfg->snapshotDir) < 0) {
VIR_WARN("failed to set parent snapshot '%s' as current", VIR_WARN("failed to set parent snapshot '%s' as current",
snap->def->parent); snap->def->parent);
vm->current_snapshot = NULL; virDomainSnapshotSetCurrent(vm->snapshots, NULL);
} }
} }
} }
@ -8658,7 +8658,7 @@ int qemuDomainSnapshotDiscardAll(void *payload,
virQEMUSnapRemovePtr curr = data; virQEMUSnapRemovePtr curr = data;
int err; int err;
if (curr->vm->current_snapshot == snap) if (virDomainSnapshotGetCurrent(curr->vm->snapshots) == snap)
curr->current = true; curr->current = true;
err = qemuDomainSnapshotDiscard(curr->driver, curr->vm, snap, false, err = qemuDomainSnapshotDiscard(curr->driver, curr->vm, snap, false,
curr->metadata_only); curr->metadata_only);
@ -8679,8 +8679,6 @@ qemuDomainSnapshotDiscardAllMetadata(virQEMUDriverPtr driver,
rem.err = 0; rem.err = 0;
virDomainSnapshotForEach(vm->snapshots, qemuDomainSnapshotDiscardAll, virDomainSnapshotForEach(vm->snapshots, qemuDomainSnapshotDiscardAll,
&rem); &rem);
if (rem.current)
vm->current_snapshot = NULL;
if (virDomainSnapshotUpdateRelations(vm->snapshots) < 0 && !rem.err) if (virDomainSnapshotUpdateRelations(vm->snapshots) < 0 && !rem.err)
rem.err = -1; rem.err = -1;

View File

@ -497,7 +497,7 @@ qemuDomainSnapshotLoad(virDomainObjPtr vm,
_("Failed to fully read directory %s"), _("Failed to fully read directory %s"),
snapDir); snapDir);
vm->current_snapshot = current; virDomainSnapshotSetCurrent(vm->snapshots, current);
if (virDomainSnapshotUpdateRelations(vm->snapshots) < 0) if (virDomainSnapshotUpdateRelations(vm->snapshots) < 0)
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
_("Snapshots have inconsistent relations for domain %s"), _("Snapshots have inconsistent relations for domain %s"),
@ -15854,13 +15854,13 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
def = NULL; def = NULL;
} }
current = vm->current_snapshot; current = virDomainSnapshotGetCurrent(vm->snapshots);
if (current) { if (current) {
if (!redefine && if (!redefine &&
VIR_STRDUP(snap->def->parent, current->def->name) < 0) VIR_STRDUP(snap->def->parent, current->def->name) < 0)
goto endjob; goto endjob;
if (update_current) { if (update_current) {
vm->current_snapshot = NULL; virDomainSnapshotSetCurrent(vm->snapshots, NULL);
if (qemuDomainSnapshotWriteMetadata(vm, current, if (qemuDomainSnapshotWriteMetadata(vm, current,
driver->caps, driver->xmlopt, driver->caps, driver->xmlopt,
cfg->snapshotDir) < 0) cfg->snapshotDir) < 0)
@ -15911,7 +15911,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
endjob: endjob:
if (snapshot && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) { if (snapshot && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
if (update_current) if (update_current)
vm->current_snapshot = snap; virDomainSnapshotSetCurrent(vm->snapshots, snap);
if (qemuDomainSnapshotWriteMetadata(vm, snap, driver->caps, if (qemuDomainSnapshotWriteMetadata(vm, snap, driver->caps,
driver->xmlopt, driver->xmlopt,
cfg->snapshotDir) < 0) { cfg->snapshotDir) < 0) {
@ -15923,7 +15923,6 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
_("unable to save metadata for snapshot %s"), _("unable to save metadata for snapshot %s"),
snap->def->name); snap->def->name);
virDomainSnapshotObjListRemove(vm->snapshots, snap); virDomainSnapshotObjListRemove(vm->snapshots, snap);
vm->current_snapshot = NULL;
} else { } else {
other = virDomainSnapshotFindByName(vm->snapshots, other = virDomainSnapshotFindByName(vm->snapshots,
snap->def->parent); snap->def->parent);
@ -16162,7 +16161,7 @@ qemuDomainHasCurrentSnapshot(virDomainPtr domain,
if (virDomainHasCurrentSnapshotEnsureACL(domain->conn, vm->def) < 0) if (virDomainHasCurrentSnapshotEnsureACL(domain->conn, vm->def) < 0)
goto cleanup; goto cleanup;
ret = (vm->current_snapshot != NULL); ret = (virDomainSnapshotGetCurrent(vm->snapshots) != NULL);
cleanup: cleanup:
virDomainObjEndAPI(&vm); virDomainObjEndAPI(&vm);
@ -16219,13 +16218,13 @@ qemuDomainSnapshotCurrent(virDomainPtr domain,
if (virDomainSnapshotCurrentEnsureACL(domain->conn, vm->def) < 0) if (virDomainSnapshotCurrentEnsureACL(domain->conn, vm->def) < 0)
goto cleanup; goto cleanup;
if (!vm->current_snapshot) { if (!virDomainSnapshotGetCurrent(vm->snapshots)) {
virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s", virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
_("the domain does not have a current snapshot")); _("the domain does not have a current snapshot"));
goto cleanup; goto cleanup;
} }
snapshot = virGetDomainSnapshot(domain, vm->current_snapshot->def->name); snapshot = virGetDomainSnapshot(domain, virDomainSnapshotGetCurrentName(vm->snapshots));
cleanup: cleanup:
virDomainObjEndAPI(&vm); virDomainObjEndAPI(&vm);
@ -16285,8 +16284,7 @@ qemuDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot))) if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
goto cleanup; goto cleanup;
ret = (vm->current_snapshot && ret = virDomainSnapshotIsCurrentName(vm->snapshots, snapshot->name);
STREQ(snapshot->name, vm->current_snapshot->def->name));
cleanup: cleanup:
virDomainObjEndAPI(&vm); virDomainObjEndAPI(&vm);
@ -16439,14 +16437,14 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
} }
} }
current = vm->current_snapshot; current = virDomainSnapshotGetCurrent(vm->snapshots);
if (current) { if (current) {
vm->current_snapshot = NULL; virDomainSnapshotSetCurrent(vm->snapshots, NULL);
if (qemuDomainSnapshotWriteMetadata(vm, current, if (qemuDomainSnapshotWriteMetadata(vm, current,
driver->caps, driver->xmlopt, driver->caps, driver->xmlopt,
cfg->snapshotDir) < 0) cfg->snapshotDir) < 0)
goto endjob; goto endjob;
/* XXX Should we restore vm->current_snapshot after this point /* XXX Should we restore the current snapshot after this point
* in the failure cases where we know there was no change? */ * in the failure cases where we know there was no change? */
} }
@ -16455,7 +16453,6 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
* *
* XXX Should domain snapshots track live xml rather * XXX Should domain snapshots track live xml rather
* than inactive xml? */ * than inactive xml? */
vm->current_snapshot = snap;
if (snap->def->dom) { if (snap->def->dom) {
config = virDomainDefCopy(snap->def->dom, caps, config = virDomainDefCopy(snap->def->dom, caps,
driver->xmlopt, NULL, true); driver->xmlopt, NULL, true);
@ -16726,15 +16723,15 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
cleanup: cleanup:
if (ret == 0) { if (ret == 0) {
vm->current_snapshot = snap; virDomainSnapshotSetCurrent(vm->snapshots, snap);
if (qemuDomainSnapshotWriteMetadata(vm, snap, driver->caps, if (qemuDomainSnapshotWriteMetadata(vm, snap, driver->caps,
driver->xmlopt, driver->xmlopt,
cfg->snapshotDir) < 0) { cfg->snapshotDir) < 0) {
vm->current_snapshot = NULL; virDomainSnapshotSetCurrent(vm->snapshots, NULL);
ret = -1; ret = -1;
} }
} else if (snap) { } else if (snap) {
vm->current_snapshot = NULL; virDomainSnapshotSetCurrent(vm->snapshots, NULL);
} }
if (ret == 0 && config && vm->persistent && if (ret == 0 && config && vm->persistent &&
!(ret = virDomainSaveConfig(cfg->configDir, driver->caps, !(ret = virDomainSaveConfig(cfg->configDir, driver->caps,
@ -16862,7 +16859,7 @@ qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
if (rem.err < 0) if (rem.err < 0)
goto endjob; goto endjob;
if (rem.current) { if (rem.current) {
vm->current_snapshot = snap; virDomainSnapshotSetCurrent(vm->snapshots, snap);
if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) { if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
if (qemuDomainSnapshotWriteMetadata(vm, snap, driver->caps, if (qemuDomainSnapshotWriteMetadata(vm, snap, driver->caps,
driver->xmlopt, driver->xmlopt,
@ -16870,7 +16867,7 @@ qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to set snapshot '%s' as current"), _("failed to set snapshot '%s' as current"),
snap->def->name); snap->def->name);
vm->current_snapshot = NULL; virDomainSnapshotSetCurrent(vm->snapshots, NULL);
goto endjob; goto endjob;
} }
} }

View File

@ -845,13 +845,13 @@ testParseDomainSnapshots(testDriverPtr privconn,
} }
if (cur) { if (cur) {
if (domobj->current_snapshot) { if (virDomainSnapshotGetCurrent(domobj->snapshots)) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("more than one snapshot claims to be active")); _("more than one snapshot claims to be active"));
goto error; goto error;
} }
domobj->current_snapshot = snap; virDomainSnapshotSetCurrent(domobj->snapshots, snap);
} }
} }
@ -6151,7 +6151,7 @@ testDomainHasCurrentSnapshot(virDomainPtr domain,
if (!(vm = testDomObjFromDomain(domain))) if (!(vm = testDomObjFromDomain(domain)))
return -1; return -1;
ret = (vm->current_snapshot != NULL); ret = (virDomainSnapshotGetCurrent(vm->snapshots) != NULL);
virDomainObjEndAPI(&vm); virDomainObjEndAPI(&vm);
return ret; return ret;
@ -6193,19 +6193,21 @@ testDomainSnapshotCurrent(virDomainPtr domain,
{ {
virDomainObjPtr vm; virDomainObjPtr vm;
virDomainSnapshotPtr snapshot = NULL; virDomainSnapshotPtr snapshot = NULL;
virDomainSnapshotObjPtr current;
virCheckFlags(0, NULL); virCheckFlags(0, NULL);
if (!(vm = testDomObjFromDomain(domain))) if (!(vm = testDomObjFromDomain(domain)))
return NULL; return NULL;
if (!vm->current_snapshot) { current = virDomainSnapshotGetCurrent(vm->snapshots);
if (!current) {
virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s", virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
_("the domain does not have a current snapshot")); _("the domain does not have a current snapshot"));
goto cleanup; goto cleanup;
} }
snapshot = virGetDomainSnapshot(domain, vm->current_snapshot->def->name); snapshot = virGetDomainSnapshot(domain, current->def->name);
cleanup: cleanup:
virDomainObjEndAPI(&vm); virDomainObjEndAPI(&vm);
@ -6253,8 +6255,7 @@ testDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
if (!(vm = testDomObjFromSnapshot(snapshot))) if (!(vm = testDomObjFromSnapshot(snapshot)))
return -1; return -1;
ret = (vm->current_snapshot && ret = virDomainSnapshotIsCurrentName(vm->snapshots, snapshot->name);
STREQ(snapshot->name, vm->current_snapshot->def->name));
virDomainObjEndAPI(&vm); virDomainObjEndAPI(&vm);
return ret; return ret;
@ -6393,9 +6394,8 @@ testDomainSnapshotCreateXML(virDomainPtr domain,
} }
if (!redefine) { if (!redefine) {
if (vm->current_snapshot && if (VIR_STRDUP(snap->def->parent,
(VIR_STRDUP(snap->def->parent, virDomainSnapshotGetCurrentName(vm->snapshots)) < 0)
vm->current_snapshot->def->name) < 0))
goto cleanup; goto cleanup;
if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) && if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) &&
@ -6413,7 +6413,7 @@ testDomainSnapshotCreateXML(virDomainPtr domain,
if (snapshot) { if (snapshot) {
virDomainSnapshotObjPtr other; virDomainSnapshotObjPtr other;
if (update_current) if (update_current)
vm->current_snapshot = snap; virDomainSnapshotSetCurrent(vm->snapshots, snap);
other = virDomainSnapshotFindByName(vm->snapshots, other = virDomainSnapshotFindByName(vm->snapshots,
snap->def->parent); snap->def->parent);
snap->parent = other; snap->parent = other;
@ -6444,9 +6444,7 @@ testDomainSnapshotDiscardAll(void *payload,
virDomainSnapshotObjPtr snap = payload; virDomainSnapshotObjPtr snap = payload;
testSnapRemoveDataPtr curr = data; testSnapRemoveDataPtr curr = data;
if (curr->vm->current_snapshot == snap) curr->current |= virDomainSnapshotObjListRemove(curr->vm->snapshots, snap);
curr->current = true;
virDomainSnapshotObjListRemove(curr->vm->snapshots, snap);
return 0; return 0;
} }
@ -6511,7 +6509,7 @@ testDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
testDomainSnapshotDiscardAll, testDomainSnapshotDiscardAll,
&rem); &rem);
if (rem.current) if (rem.current)
vm->current_snapshot = snap; virDomainSnapshotSetCurrent(vm->snapshots, snap);
} else if (snap->nchildren) { } else if (snap->nchildren) {
testSnapReparentData rep; testSnapReparentData rep;
rep.parent = snap->parent; rep.parent = snap->parent;
@ -6535,7 +6533,7 @@ testDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
snap->first_child = NULL; snap->first_child = NULL;
} else { } else {
virDomainSnapshotDropParent(snap); virDomainSnapshotDropParent(snap);
if (snap == vm->current_snapshot) { if (snap == virDomainSnapshotGetCurrent(vm->snapshots)) {
if (snap->def->parent) { if (snap->def->parent) {
parentsnap = virDomainSnapshotFindByName(vm->snapshots, parentsnap = virDomainSnapshotFindByName(vm->snapshots,
snap->def->parent); snap->def->parent);
@ -6543,7 +6541,7 @@ testDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
VIR_WARN("missing parent snapshot matching name '%s'", VIR_WARN("missing parent snapshot matching name '%s'",
snap->def->parent); snap->def->parent);
} }
vm->current_snapshot = parentsnap; virDomainSnapshotSetCurrent(vm->snapshots, parentsnap);
} }
virDomainSnapshotObjListRemove(vm->snapshots, snap); virDomainSnapshotObjListRemove(vm->snapshots, snap);
} }
@ -6619,9 +6617,7 @@ testDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
} }
} }
virDomainSnapshotSetCurrent(vm->snapshots, NULL);
if (vm->current_snapshot)
vm->current_snapshot = NULL;
config = virDomainDefCopy(snap->def->dom, privconn->caps, config = virDomainDefCopy(snap->def->dom, privconn->caps,
privconn->xmlopt, NULL, true); privconn->xmlopt, NULL, true);
@ -6746,7 +6742,7 @@ testDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
} }
} }
vm->current_snapshot = snap; virDomainSnapshotSetCurrent(vm->snapshots, snap);
ret = 0; ret = 0;
cleanup: cleanup:
if (event) { if (event) {