[libvirt] [PATCH 5/5] snapshot: Support reparenting external disk snapshots when deleting

Povilas Kanapickas povilas at radix.lt
Sun Oct 21 16:38:52 UTC 2018


Signed-off-by: Povilas Kanapickas <povilas at radix.lt>
---
 src/qemu/qemu_driver.c | 89 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 89 insertions(+)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 227ec1c6d9..a3ffc19122 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -16590,6 +16590,7 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
 typedef struct _virQEMUSnapReparent virQEMUSnapReparent;
 typedef virQEMUSnapReparent *virQEMUSnapReparentPtr;
 struct _virQEMUSnapReparent {
+    virQEMUDriverPtr driver;
     virQEMUDriverConfigPtr cfg;
     virDomainSnapshotObjPtr parent;
     virDomainObjPtr vm;
@@ -16617,6 +16618,88 @@ qemuDomainSnapshotReparentChildrenMetadata(virDomainSnapshotObjPtr snap,
                                            rep->cfg->snapshotDir);
 }
 
+static int
+qemuDomainSnapshotReparentDiskExternal(virQEMUDriverPtr driver,
+                                       virDomainSnapshotObjPtr parent_snap,
+                                       virDomainSnapshotDiskDefPtr disk)
+{
+    const char* qemu_img_path = NULL;
+    virCommandPtr cmd = NULL;
+    int i;
+    int ret = -1;
+    const char* parent_disk_path = NULL;
+
+    // Find the path to the disk we should use as the base when reparenting
+    // FIXME: what if there's no parent snapshot? i.e. we need to reparent on
+    // "empty" disk?
+    for (i = 0; i < parent_snap->def->dom->ndisks; ++i) {
+        if (STREQ(parent_snap->def->dom->disks[i]->dst, disk->name)) {
+            parent_disk_path = parent_snap->def->dom->disks[i]->src->path;
+            break;
+        }
+    }
+
+    if (parent_disk_path == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Could not find disk to reparent '%s' to"),
+                       disk->src->path);
+        goto cleanup;
+    }
+
+    if (!(qemu_img_path = qemuFindQemuImgBinary(driver))) {
+        goto cleanup;
+    }
+
+    if (!(cmd = virCommandNewArgList(qemu_img_path,
+                                     "rebase", "-b", parent_disk_path,
+                                     disk->src->path,
+                                     NULL))) {
+        goto cleanup;
+    }
+
+    if (virCommandRun(cmd, NULL) < 0)
+        goto cleanup;
+
+    ret = 0;
+cleanup:
+    virCommandFree(cmd);
+    return ret;
+}
+
+static int
+qemuDomainSnapshotReparentDisks(virDomainSnapshotObjPtr snap,
+                                virQEMUSnapReparentPtr rep)
+{
+    int i;
+    virDomainSnapshotDiskDefPtr snap_disk;
+
+    if (!snap->def->dom) {
+        VIR_WARN("Any external disk snapshots in a snapshot created with "
+                 "pre-0.9.5 libvirt will not be correctly reparented.");
+        // In snapshots created with pre-0.9.5 libvirt we don't have information
+        // needed to correctly reparent external disk snapshots but we also
+        // don't even know whether external disk snapshots were used so that
+        // we could report this as an error. We can only emit a warning in that
+        // case.
+        return 0;
+    }
+
+    for (i = 0; i < snap->def->ndisks; ++i) {
+        snap_disk = &(snap->def->disks[i]);
+
+        // FIXME: do we need to explicitly reparent internal snapshots to
+        // e.g. prevent long non-visible snapshot chains that might affect
+        // performance?
+        if (snap_disk->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL)
+            continue;
+
+        if (qemuDomainSnapshotReparentDiskExternal(rep->driver, rep->parent,
+                                                   snap_disk) < 0)
+            return -1;
+    }
+    return 0;
+}
+
 static int
 qemuDomainSnapshotReparentChildren(void *payload,
                                    const void *name ATTRIBUTE_UNUSED,
@@ -16628,6 +16711,11 @@ qemuDomainSnapshotReparentChildren(void *payload,
     if (rep->err < 0)
         return 0;
 
+    if (qemuDomainSnapshotReparentDisks(snap, rep) < 0) {
+        rep->err = -1;
+        goto cleanup;
+    }
+
     if (qemuDomainSnapshotReparentChildrenMetadata(snap, rep) < 0) {
         rep->err = -1;
         goto cleanup;
@@ -16718,6 +16806,7 @@ qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
             vm->current_snapshot = snap;
         }
     } else if (snap->nchildren) {
+        rep.driver = driver;
         rep.cfg = cfg;
         rep.parent = snap->parent;
         rep.vm = vm;
-- 
2.17.1





More information about the libvir-list mailing list