]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu: snapshot: Write metadata of previously-'current' snapshot on update
authorPeter Krempa <pkrempa@redhat.com>
Mon, 23 Nov 2020 10:56:12 +0000 (11:56 +0100)
committerPeter Krempa <pkrempa@redhat.com>
Tue, 24 Nov 2020 16:59:26 +0000 (17:59 +0100)
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>
src/qemu/qemu_snapshot.c

index 1c58ac8acf9425ae85de1d58e81c798748a4abb0..15494c341516ce81cd086d1b91edeb1919733773 100644 (file)
 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,