提交 6766ff10 编写于 作者: E Eric Blake

snapshot: track current snapshot across restarts

Audit all changes to the qemu vm->current_snapshot, and make them
update the saved xml file for both the previous and the new
snapshot, so that there is always at most one snapshot with
<active>1</active> in the xml, and that snapshot is used as the
current snapshot even across libvirtd restarts.

This patch does not fix the case of virDomainSnapshotDelete(,CHILDREN)
where one of the children is the current snapshot; that will be later.

* src/conf/domain_conf.h (_virDomainSnapshotDef): Alter member
type and name.
* src/conf/domain_conf.c (virDomainSnapshotDefParseString)
(virDomainSnapshotDefFormat): Update clients.
* docs/schemas/domainsnapshot.rng: Tighten rng.
* src/qemu/qemu_driver.c (qemuDomainSnapshotLoad): Reload current
snapshot.
(qemuDomainSnapshotCreateXML, qemuDomainRevertToSnapshot)
(qemuDomainSnapshotDiscard): Track current snapshot.
上级 5e47785b
...@@ -29,7 +29,10 @@ ...@@ -29,7 +29,10 @@
</optional> </optional>
<optional> <optional>
<element name='active'> <element name='active'>
<text/> <choice>
<value>0</value>
<value>1</value>
</choice>
</element> </element>
</optional> </optional>
<optional> <optional>
......
...@@ -10960,6 +10960,7 @@ virDomainSnapshotDefPtr virDomainSnapshotDefParseString(const char *xmlStr, ...@@ -10960,6 +10960,7 @@ virDomainSnapshotDefPtr virDomainSnapshotDefParseString(const char *xmlStr,
virDomainSnapshotDefPtr ret = NULL; virDomainSnapshotDefPtr ret = NULL;
char *creation = NULL, *state = NULL; char *creation = NULL, *state = NULL;
struct timeval tv; struct timeval tv;
int active;
xml = virXMLParseCtxt(NULL, xmlStr, "domainsnapshot.xml", &ctxt); xml = virXMLParseCtxt(NULL, xmlStr, "domainsnapshot.xml", &ctxt);
if (!xml) { if (!xml) {
...@@ -11016,11 +11017,12 @@ virDomainSnapshotDefPtr virDomainSnapshotDefParseString(const char *xmlStr, ...@@ -11016,11 +11017,12 @@ virDomainSnapshotDefPtr virDomainSnapshotDefParseString(const char *xmlStr,
goto cleanup; goto cleanup;
} }
if (virXPathLong("string(./active)", ctxt, &def->active) < 0) { if (virXPathInt("string(./active)", ctxt, &active) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s", virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not find 'active' element")); _("Could not find 'active' element"));
goto cleanup; goto cleanup;
} }
def->current = active != 0;
} }
else else
def->creationTime = tv.tv_sec; def->creationTime = tv.tv_sec;
...@@ -11062,7 +11064,7 @@ char *virDomainSnapshotDefFormat(char *domain_uuid, ...@@ -11062,7 +11064,7 @@ char *virDomainSnapshotDefFormat(char *domain_uuid,
virBufferAsprintf(&buf, " <uuid>%s</uuid>\n", domain_uuid); virBufferAsprintf(&buf, " <uuid>%s</uuid>\n", domain_uuid);
virBufferAddLit(&buf, " </domain>\n"); virBufferAddLit(&buf, " </domain>\n");
if (internal) if (internal)
virBufferAsprintf(&buf, " <active>%ld</active>\n", def->active); virBufferAsprintf(&buf, " <active>%d</active>\n", def->current);
virBufferAddLit(&buf, "</domainsnapshot>\n"); virBufferAddLit(&buf, "</domainsnapshot>\n");
if (virBufferError(&buf)) { if (virBufferError(&buf)) {
......
...@@ -1297,13 +1297,15 @@ enum virDomainTaintFlags { ...@@ -1297,13 +1297,15 @@ enum virDomainTaintFlags {
typedef struct _virDomainSnapshotDef virDomainSnapshotDef; typedef struct _virDomainSnapshotDef virDomainSnapshotDef;
typedef virDomainSnapshotDef *virDomainSnapshotDefPtr; typedef virDomainSnapshotDef *virDomainSnapshotDefPtr;
struct _virDomainSnapshotDef { struct _virDomainSnapshotDef {
/* Public XML. */
char *name; char *name;
char *description; char *description;
char *parent; char *parent;
long long creationTime; /* in seconds */ long long creationTime; /* in seconds */
int state; int state;
long active; /* Internal use. */
bool current; /* At most one snapshot in the list should have this set */
}; };
typedef struct _virDomainSnapshotObj virDomainSnapshotObj; typedef struct _virDomainSnapshotObj virDomainSnapshotObj;
......
...@@ -294,6 +294,7 @@ static void qemuDomainSnapshotLoad(void *payload, ...@@ -294,6 +294,7 @@ static void qemuDomainSnapshotLoad(void *payload,
char *fullpath; char *fullpath;
virDomainSnapshotDefPtr def = NULL; virDomainSnapshotDefPtr def = NULL;
virDomainSnapshotObjPtr snap = NULL; virDomainSnapshotObjPtr snap = NULL;
virDomainSnapshotObjPtr current = NULL;
char ebuf[1024]; char ebuf[1024];
virDomainObjLock(vm); virDomainObjLock(vm);
...@@ -339,7 +340,8 @@ static void qemuDomainSnapshotLoad(void *payload, ...@@ -339,7 +340,8 @@ static void qemuDomainSnapshotLoad(void *payload,
def = virDomainSnapshotDefParseString(xmlStr, 0); def = virDomainSnapshotDefParseString(xmlStr, 0);
if (def == NULL) { if (def == NULL) {
/* Nothing we can do here, skip this one */ /* Nothing we can do here, skip this one */
VIR_ERROR(_("Failed to parse snapshot XML from file '%s'"), fullpath); VIR_ERROR(_("Failed to parse snapshot XML from file '%s'"),
fullpath);
VIR_FREE(fullpath); VIR_FREE(fullpath);
VIR_FREE(xmlStr); VIR_FREE(xmlStr);
continue; continue;
...@@ -348,12 +350,22 @@ static void qemuDomainSnapshotLoad(void *payload, ...@@ -348,12 +350,22 @@ static void qemuDomainSnapshotLoad(void *payload,
snap = virDomainSnapshotAssignDef(&vm->snapshots, def); snap = virDomainSnapshotAssignDef(&vm->snapshots, def);
if (snap == NULL) { if (snap == NULL) {
virDomainSnapshotDefFree(def); virDomainSnapshotDefFree(def);
} else if (snap->def->current) {
current = snap;
if (!vm->current_snapshot)
vm->current_snapshot = snap;
} }
VIR_FREE(fullpath); VIR_FREE(fullpath);
VIR_FREE(xmlStr); VIR_FREE(xmlStr);
} }
if (vm->current_snapshot != current) {
VIR_ERROR(_("Too many snapshots claiming to be current for domain %s"),
vm->def->name);
vm->current_snapshot = NULL;
}
/* FIXME: qemu keeps internal track of snapshots. We can get access /* FIXME: qemu keeps internal track of snapshots. We can get access
* to this info via the "info snapshots" monitor command for running * to this info via the "info snapshots" monitor command for running
* domains, or via "qemu-img snapshot -l" for shutoff domains. It would * domains, or via "qemu-img snapshot -l" for shutoff domains. It would
...@@ -8477,12 +8489,17 @@ static virDomainSnapshotPtr qemuDomainSnapshotCreateXML(virDomainPtr domain, ...@@ -8477,12 +8489,17 @@ static virDomainSnapshotPtr qemuDomainSnapshotCreateXML(virDomainPtr domain,
def = NULL; def = NULL;
snap->def->state = virDomainObjGetState(vm, NULL); snap->def->state = virDomainObjGetState(vm, NULL);
snap->def->current = true;
if (vm->current_snapshot) { if (vm->current_snapshot) {
snap->def->parent = strdup(vm->current_snapshot->def->name); snap->def->parent = strdup(vm->current_snapshot->def->name);
if (snap->def->parent == NULL) { if (snap->def->parent == NULL) {
virReportOOMError(); virReportOOMError();
goto cleanup; goto cleanup;
} }
vm->current_snapshot->def->current = false;
if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
driver->snapshotDir) < 0)
goto cleanup;
vm->current_snapshot = NULL; vm->current_snapshot = NULL;
} }
...@@ -8502,6 +8519,7 @@ static virDomainSnapshotPtr qemuDomainSnapshotCreateXML(virDomainPtr domain, ...@@ -8502,6 +8519,7 @@ static virDomainSnapshotPtr qemuDomainSnapshotCreateXML(virDomainPtr domain,
*/ */
if (qemuDomainSnapshotWriteMetadata(vm, snap, driver->snapshotDir) < 0) if (qemuDomainSnapshotWriteMetadata(vm, snap, driver->snapshotDir) < 0)
goto cleanup; goto cleanup;
vm->current_snapshot = snap;
snapshot = virGetDomainSnapshot(domain, snap->def->name); snapshot = virGetDomainSnapshot(domain, snap->def->name);
...@@ -8742,7 +8760,17 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, ...@@ -8742,7 +8760,17 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
goto cleanup; goto cleanup;
} }
vm->current_snapshot = snap; if (vm->current_snapshot) {
vm->current_snapshot->def->current = false;
if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
driver->snapshotDir) < 0)
goto cleanup;
vm->current_snapshot = NULL;
/* XXX Should we restore vm->current_snapshot after this point
* in the failure cases where we know there was no change? */
}
snap->def->current = true;
if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0) if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
goto cleanup; goto cleanup;
...@@ -8759,7 +8787,7 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, ...@@ -8759,7 +8787,7 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
goto endjob; goto endjob;
} else { } else {
rc = qemuProcessStart(snapshot->domain->conn, driver, vm, NULL, rc = qemuProcessStart(snapshot->domain->conn, driver, vm, NULL,
false, false, -1, NULL, vm->current_snapshot, false, false, -1, NULL, snap,
VIR_VM_OP_CREATE); VIR_VM_OP_CREATE);
virDomainAuditStart(vm, "from-snapshot", rc >= 0); virDomainAuditStart(vm, "from-snapshot", rc >= 0);
if (rc < 0) if (rc < 0)
...@@ -8817,6 +8845,15 @@ endjob: ...@@ -8817,6 +8845,15 @@ endjob:
vm = NULL; vm = NULL;
cleanup: cleanup:
if (vm && ret == 0) {
if (qemuDomainSnapshotWriteMetadata(vm, snap,
driver->snapshotDir) < 0)
ret = -1;
else
vm->current_snapshot = snap;
} else if (snap) {
snap->def->current = false;
}
if (event) if (event)
qemuDomainEventQueue(driver, event); qemuDomainEventQueue(driver, event);
if (vm) if (vm)
...@@ -8835,7 +8872,7 @@ static int qemuDomainSnapshotDiscard(struct qemud_driver *driver, ...@@ -8835,7 +8872,7 @@ static int qemuDomainSnapshotDiscard(struct qemud_driver *driver,
int ret = -1; int ret = -1;
int i; int i;
qemuDomainObjPrivatePtr priv; qemuDomainObjPrivatePtr priv;
virDomainSnapshotObjPtr parentsnap; virDomainSnapshotObjPtr parentsnap = NULL;
if (!virDomainObjIsActive(vm)) { if (!virDomainObjIsActive(vm)) {
qemuimgarg[0] = qemuFindQemuImgBinary(); qemuimgarg[0] = qemuFindQemuImgBinary();
...@@ -8874,31 +8911,35 @@ static int qemuDomainSnapshotDiscard(struct qemud_driver *driver, ...@@ -8874,31 +8911,35 @@ static int qemuDomainSnapshotDiscard(struct qemud_driver *driver,
qemuDomainObjExitMonitorWithDriver(driver, vm); qemuDomainObjExitMonitorWithDriver(driver, vm);
} }
if (virAsprintf(&snapFile, "%s/%s/%s.xml", driver->snapshotDir,
vm->def->name, snap->def->name) < 0) {
virReportOOMError();
goto cleanup;
}
if (snap == vm->current_snapshot) { if (snap == vm->current_snapshot) {
if (snap->def->parent) { if (snap->def->parent) {
parentsnap = virDomainSnapshotFindByName(&vm->snapshots, parentsnap = virDomainSnapshotFindByName(&vm->snapshots,
snap->def->parent); snap->def->parent);
if (!parentsnap) { if (!parentsnap) {
qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, VIR_WARN("missing parent snapshot matching name '%s'",
_("no domain snapshot parent with matching name '%s'"),
snap->def->parent); snap->def->parent);
goto cleanup;
}
/* Now we set the new current_snapshot for the domain */
vm->current_snapshot = parentsnap;
} else { } else {
vm->current_snapshot = NULL; parentsnap->def->current = true;
if (qemuDomainSnapshotWriteMetadata(vm, parentsnap,
driver->snapshotDir) < 0) {
VIR_WARN("failed to set parent snapshot '%s' as current",
snap->def->parent);
parentsnap->def->current = false;
parentsnap = NULL;
} }
} }
if (virAsprintf(&snapFile, "%s/%s/%s.xml", driver->snapshotDir,
vm->def->name, snap->def->name) < 0) {
virReportOOMError();
goto cleanup;
} }
unlink(snapFile); vm->current_snapshot = parentsnap;
}
if (unlink(snapFile) < 0)
VIR_WARN("Failed to unlink %s", snapFile);
virDomainSnapshotObjListRemove(&vm->snapshots, snap); virDomainSnapshotObjListRemove(&vm->snapshots, snap);
ret = 0; ret = 0;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册