[libvirt RFC 22/24] qemu_snapshot: update metadata when deleting snapshots

Pavel Hrdina phrdina at redhat.com
Tue Aug 23 16:32:25 UTC 2022


With external snapshots we need to modify the metadata bit more then
what is required for internal snapshots. Mainly the storage source
location changes with every external snapshot.

This means that if we delete non-leaf snapshot we need to update all
children snapshots and modify the disk sources for all affected disks.

Signed-off-by: Pavel Hrdina <phrdina at redhat.com>
---
 src/qemu/qemu_snapshot.c | 116 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)

diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c
index 64ee395230..37ae3f04d0 100644
--- a/src/qemu/qemu_snapshot.c
+++ b/src/qemu/qemu_snapshot.c
@@ -2380,6 +2380,109 @@ qemuSnapshotChildrenReparent(void *payload,
 }
 
 
+typedef struct _qemuSnapshotUpdateDisksData qemuSnapshotUpdateDisksData;
+struct _qemuSnapshotUpdateDisksData {
+    virDomainMomentObj *snap;
+    virDomainObj *vm;
+    virQEMUDriver *driver;
+    int error;
+    int (*writeMetadata)(virDomainObj *, virDomainMomentObj *,
+                         virDomainXMLOption *, const char *);
+};
+
+
+static int
+qemuSnapshotUpdateDisksSingle(virDomainMomentObj *snap,
+                              virDomainDef *def,
+                              virDomainDef *parentDef,
+                              virDomainSnapshotDiskDef *snapDisk)
+{
+    virDomainDiskDef *disk = NULL;
+
+    if (!(disk = qemuDomainDiskByName(def, snapDisk->name)))
+        return -1;
+
+    if (virDomainSnapshotIsExternal(snap)) {
+        virDomainDiskDef *parentDisk = NULL;
+
+        if (!(parentDisk = qemuDomainDiskByName(parentDef, snapDisk->name)))
+            return -1;
+
+        if (virStorageSourceIsSameLocation(snapDisk->src, disk->src)) {
+            virObjectUnref(disk->src);
+            disk->src = virStorageSourceCopy(parentDisk->src, false);
+        }
+    }
+
+    if (disk->src->backingStore) {
+        virStorageSource *cur = disk->src;
+        virStorageSource *next = disk->src->backingStore;
+
+        while (next) {
+            if (virStorageSourceIsSameLocation(snapDisk->src, next)) {
+                cur->backingStore = next->backingStore;
+                next->backingStore = NULL;
+                virObjectUnref(next);
+                break;
+            }
+
+            cur = next;
+            next = cur->backingStore;
+        }
+    }
+
+    return 0;
+}
+
+
+static int
+qemuSnapshotDeleteUpdateDisks(void *payload,
+                              const char *name G_GNUC_UNUSED,
+                              void *opaque)
+{
+    virDomainMomentObj *snap = payload;
+    qemuSnapshotUpdateDisksData *data = opaque;
+    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(data->driver);
+    virDomainSnapshotDef *snapdef = virDomainSnapshotObjGetDef(data->snap);
+    ssize_t i;
+
+    if (data->error < 0)
+        return 0;
+
+    for (i = 0; i < snapdef->ndisks; i++) {
+        virDomainSnapshotDiskDef *snapDisk = &(snapdef->disks[i]);
+
+        if (snapDisk->snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NO)
+            continue;
+
+        if (qemuSnapshotUpdateDisksSingle(snap, snap->def->dom,
+                                          data->snap->def->dom, snapDisk) < 0) {
+            data->error = -1;
+            return 0;
+        }
+
+        if (snap->def->inactiveDom) {
+            virDomainDef *dom = data->snap->def->inactiveDom;
+
+            if (!dom)
+                dom = data->snap->def->dom;
+
+            if (qemuSnapshotUpdateDisksSingle(snap, snap->def->inactiveDom,
+                                              dom, snapDisk) < 0) {
+                data->error = -1;
+                return 0;
+            }
+        }
+    }
+
+    data->error = data->writeMetadata(data->vm,
+                                      snap,
+                                      data->driver->xmlopt,
+                                      cfg->snapshotDir);
+    return 0;
+}
+
+
 static int
 qemuSnapshotJobRunning(virDomainObj *vm,
                        qemuBlockJobData *job)
@@ -2500,6 +2603,7 @@ qemuSnapshotDiscardMetadata(virDomainObj *vm,
 
     if (update_parent && snap->nchildren) {
         virQEMUMomentReparent rep;
+        qemuSnapshotUpdateDisksData data;
 
         rep.dir = cfg->snapshotDir;
         rep.parent = snap->parent;
@@ -2512,6 +2616,18 @@ qemuSnapshotDiscardMetadata(virDomainObj *vm,
                                     &rep);
         if (rep.err < 0)
             return -1;
+
+        data.snap = snap;
+        data.driver = driver;
+        data.vm = vm;
+        data.error = 0;
+        data.writeMetadata = qemuDomainSnapshotWriteMetadata;
+        virDomainMomentForEachDescendant(snap,
+                                         qemuSnapshotDeleteUpdateDisks,
+                                         &data);
+        if (data.error < 0)
+            return -1;
+
         virDomainMomentMoveChildren(snap, snap->parent);
     }
 
-- 
2.37.2



More information about the libvir-list mailing list