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 <pkre...@redhat.com>
---
 src/qemu/qemu_snapshot.c | 38 +++++++++++++++++++++++++++++++++++---
 1 file changed, 35 insertions(+), 3 deletions(-)

diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c
index 057b94e5b8..6ed2ce838c 100644
--- a/src/qemu/qemu_snapshot.c
+++ b/src/qemu/qemu_snapshot.c
@@ -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) {
@@ -2233,7 +2264,7 @@ qemuSnapshotRevert(virDomainObjPtr vm,

  cleanup:
     if (ret == 0) {
-        virDomainSnapshotSetCurrent(vm->snapshots, snap);
+        qemuSnapshotSetCurrent(vm, snap);
         if (qemuDomainSnapshotWriteMetadata(vm, snap,
                                             driver->xmlopt,
                                             cfg->snapshotDir) < 0) {
@@ -2350,7 +2381,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,
-- 
2.28.0

Reply via email to