qemu: snapshot: Write metadata of previously-'current' snapshot on update

Whether a snapshot definition is considered 'current' or active is
stored in the metadata XML libvirt writes when we create metadata.

This means that if we are changing the 'current' snapshot we must
re-write the metadata of the previously 'current' snapshot to update the
field to prevent having multiple active snapshots.

Unfortunately the snapshot creation code didn't do this properly, which
resulted in the following error:

error : qemuDomainSnapshotLoad:430 : internal error: Too many snapshots claiming to be current for domain snapshot-test

being printed if libvirtd was terminated and restarted.

Introduce qemuSnapshotSetCurrent which writes out the old snapshot's
metadata when updating the current snapshot.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
Peter Krempa 2020-11-23 11:56:12 +01:00
parent 926563dc3a
commit 5d8acaa8bc

View File

@ -47,6 +47,36 @@
VIR_LOG_INIT("qemu.qemu_snapshot");
/**
* qemuSnapshotSetCurrent: Set currently active snapshot
*
* @vm: domain object
* @newcurrent: snapshot object to set as current/active
*
* Sets @newcurrent as the 'current' snapshot of @vm. This helper ensures that
* the snapshot which was 'current' previously is updated.
*/
static void
qemuSnapshotSetCurrent(virDomainObjPtr vm,
virDomainMomentObjPtr newcurrent)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
virQEMUDriverPtr driver = priv->driver;
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
virDomainMomentObjPtr oldcurrent = virDomainSnapshotGetCurrent(vm->snapshots);
virDomainSnapshotSetCurrent(vm->snapshots, newcurrent);
/* we need to write out metadata for the old snapshot to update the
* 'active' property */
if (oldcurrent &&
oldcurrent != newcurrent) {
if (qemuDomainSnapshotWriteMetadata(vm, oldcurrent, driver->xmlopt, cfg->snapshotDir) < 0)
VIR_WARN("failed to update old current snapshot");
}
}
/* Looks up snapshot object from VM and name */
virDomainMomentObjPtr
qemuSnapObjFromName(virDomainObjPtr vm,
@ -1781,7 +1811,8 @@ qemuSnapshotCreateXML(virDomainPtr domain,
endjob:
if (snapshot && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
if (update_current)
virDomainSnapshotSetCurrent(vm->snapshots, snap);
qemuSnapshotSetCurrent(vm, snap);
if (qemuDomainSnapshotWriteMetadata(vm, snap,
driver->xmlopt,
cfg->snapshotDir) < 0) {
@ -2243,7 +2274,7 @@ qemuSnapshotRevert(virDomainObjPtr vm,
cleanup:
if (ret == 0) {
virDomainSnapshotSetCurrent(vm->snapshots, snap);
qemuSnapshotSetCurrent(vm, snap);
if (qemuDomainSnapshotWriteMetadata(vm, snap,
driver->xmlopt,
cfg->snapshotDir) < 0) {
@ -2360,7 +2391,8 @@ qemuSnapshotDelete(virDomainObjPtr vm,
if (rem.err < 0)
goto endjob;
if (rem.found) {
virDomainSnapshotSetCurrent(vm->snapshots, snap);
qemuSnapshotSetCurrent(vm, snap);
if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
if (qemuDomainSnapshotWriteMetadata(vm, snap,
driver->xmlopt,