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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxx>
---
 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




[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux