[libvirt] [PATCH 09/10] qemu: Add -blockdev support for external snapshots

Peter Krempa pkrempa at redhat.com
Fri Aug 16 13:54:43 UTC 2019


Use the code for creating or attaching new storage source in the
snapshot code and switch to 'blockdev-snapshot' for creating the
snapshot itself.

Signed-off-by: Peter Krempa <pkrempa at redhat.com>
---
 src/qemu/qemu_driver.c | 104 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 88 insertions(+), 16 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 6e10b691e9..c22f74adaa 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -15270,6 +15270,8 @@ struct _qemuDomainSnapshotDiskData {
     bool prepared; /* @src was prepared using qemuDomainStorageSourceAccessAllow */
     virDomainDiskDefPtr disk;
     char *relPath; /* relative path component to fill into original disk */
+    qemuBlockStorageSourceChainDataPtr crdata;
+    bool blockdevadded;

     virStorageSourcePtr persistsrc;
     virDomainDiskDefPtr persistdisk;
@@ -15283,7 +15285,8 @@ static void
 qemuDomainSnapshotDiskDataCleanup(qemuDomainSnapshotDiskDataPtr data,
                                   size_t ndata,
                                   virQEMUDriverPtr driver,
-                                  virDomainObjPtr vm)
+                                  virDomainObjPtr vm,
+                                  qemuDomainAsyncJob asyncJob)
 {
     size_t i;

@@ -15294,6 +15297,15 @@ qemuDomainSnapshotDiskDataCleanup(qemuDomainSnapshotDiskDataPtr data,
         /* on success of the snapshot the 'src' and 'persistsrc' properties will
          * be set to NULL by qemuDomainSnapshotUpdateDiskSources */
         if (data[i].src) {
+            if (data[i].blockdevadded) {
+                if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) == 0) {
+
+                    qemuBlockStorageSourceAttachRollback(qemuDomainGetMonitor(vm),
+                                                         data[i].crdata->srcdata[0]);
+                    ignore_value(qemuDomainObjExitMonitor(driver, vm));
+                }
+            }
+
             if (data[i].created &&
                 virStorageFileUnlink(data[i].src) < 0) {
                 VIR_WARN("Unable to remove just-created %s",
@@ -15312,6 +15324,7 @@ qemuDomainSnapshotDiskDataCleanup(qemuDomainSnapshotDiskDataPtr data,
         VIR_FREE(data[i].relPath);
     }

+    qemuBlockStorageSourceChainDataFree(data[i].crdata);
     VIR_FREE(data);
 }

@@ -15319,15 +15332,20 @@ qemuDomainSnapshotDiskDataCleanup(qemuDomainSnapshotDiskDataPtr data,
 static int
 qemuDomainSnapshotDiskDataCollectOne(virQEMUDriverPtr driver,
                                      virDomainObjPtr vm,
+                                     virQEMUDriverConfigPtr cfg,
                                      virDomainDiskDefPtr disk,
                                      virDomainSnapshotDiskDefPtr snapdisk,
                                      qemuDomainSnapshotDiskDataPtr dd,
-                                     bool reuse)
+                                     bool reuse,
+                                     bool blockdev,
+                                     qemuDomainAsyncJob asyncJob)
 {
+    qemuDomainObjPrivatePtr priv = vm->privateData;
     char *backingStoreStr;
     virDomainDiskDefPtr persistdisk;
     bool supportsCreate;
     bool supportsBacking;
+    int rc;

     dd->disk = disk;

@@ -15393,6 +15411,44 @@ qemuDomainSnapshotDiskDataCollectOne(virQEMUDriverPtr driver,

     dd->prepared = true;

+    if (blockdev) {
+        /* create a terminator for the snapsot disks so that qemu does not try
+         * to open them at first */
+        virObjectUnref(dd->src->backingStore);
+        if (!(dd->src->backingStore = virStorageSourceNew()))
+            return -1;
+
+        if (qemuDomainPrepareStorageSourceBlockdev(dd->disk, dd->src,
+                                                   priv, cfg) < 0)
+            return -1;
+
+        if (!(dd->crdata = qemuBuildStorageSourceChainAttachPrepareBlockdevTop(dd->src,
+                                                                               priv->qemuCaps)))
+            return -1;
+
+        if (reuse) {
+            if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
+                return -1;
+
+            rc = qemuBlockStorageSourceAttachApply(qemuDomainGetMonitor(vm),
+                                                   dd->crdata->srcdata[0]);
+
+            if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
+                return -1;
+        } else {
+            if (qemuBlockStorageSourceCreateDetectSize(vm, dd->src, dd->disk->src,
+                                                       asyncJob) < 0)
+                return -1;
+
+            if (qemuBlockStorageSourceCreate(vm, dd->src, dd->disk->src,
+                                             NULL, dd->crdata->srcdata[0],
+                                             asyncJob) < 0)
+                return -1;
+        }
+
+        dd->blockdevadded = true;
+    }
+
     return 0;
 }

@@ -15407,7 +15463,10 @@ static int
 qemuDomainSnapshotDiskDataCollect(virQEMUDriverPtr driver,
                                   virDomainObjPtr vm,
                                   virDomainMomentObjPtr snap,
+                                  virQEMUDriverConfigPtr cfg,
                                   bool reuse,
+                                  bool blockdev,
+                                  qemuDomainAsyncJob asyncJob,
                                   qemuDomainSnapshotDiskDataPtr *rdata,
                                   size_t *rndata)
 {
@@ -15424,9 +15483,10 @@ qemuDomainSnapshotDiskDataCollect(virQEMUDriverPtr driver,
         if (snapdef->disks[i].snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)
             continue;

-        if (qemuDomainSnapshotDiskDataCollectOne(driver, vm, vm->def->disks[i],
+        if (qemuDomainSnapshotDiskDataCollectOne(driver, vm, cfg, vm->def->disks[i],
                                                  snapdef->disks + i,
-                                                 data + ndata++, reuse) < 0)
+                                                 data + ndata++, reuse, blockdev,
+                                                 asyncJob) < 0)
             goto cleanup;
     }

@@ -15435,7 +15495,7 @@ qemuDomainSnapshotDiskDataCollect(virQEMUDriverPtr driver,
     ret = 0;

  cleanup:
-    qemuDomainSnapshotDiskDataCleanup(data, ndata, driver, vm);
+    qemuDomainSnapshotDiskDataCleanup(data, ndata, driver, vm, asyncJob);
     return ret;
 }

@@ -15456,13 +15516,15 @@ qemuDomainSnapshotUpdateDiskSourcesRenumber(virStorageSourcePtr src)
  * @driver: QEMU driver
  * @vm: domain object
  * @dd: snapshot disk data object
+ * @blockdev: -blockdev is in use for the VM
  *
  * Updates disk definition after a successful snapshot.
  */
 static void
 qemuDomainSnapshotUpdateDiskSources(virQEMUDriverPtr driver,
                                     virDomainObjPtr vm,
-                                    qemuDomainSnapshotDiskDataPtr dd)
+                                    qemuDomainSnapshotDiskDataPtr dd,
+                                    bool blockdev)
 {
     /* storage driver access won'd be needed */
     if (dd->initialized)
@@ -15475,11 +15537,13 @@ qemuDomainSnapshotUpdateDiskSources(virQEMUDriverPtr driver,
     dd->disk->src->readonly = true;

     VIR_STEAL_PTR(dd->disk->src->relPath, dd->relPath);
+    virObjectUnref(dd->src->backingStore);
     VIR_STEAL_PTR(dd->src->backingStore, dd->disk->src);
     VIR_STEAL_PTR(dd->disk->src, dd->src);

     /* fix numbering of disks */
-    qemuDomainSnapshotUpdateDiskSourcesRenumber(dd->disk->src);
+    if (!blockdev)
+        qemuDomainSnapshotUpdateDiskSourcesRenumber(dd->disk->src);

     if (dd->persistdisk) {
         VIR_STEAL_PTR(dd->persistsrc->backingStore, dd->persistdisk->src);
@@ -15506,6 +15570,7 @@ qemuDomainSnapshotCreateDiskActive(virQEMUDriverPtr driver,
     qemuDomainSnapshotDiskDataPtr diskdata = NULL;
     size_t ndiskdata = 0;
     virErrorPtr orig_err = NULL;
+    bool blockdev =  virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV);

     if (virDomainObjCheckActive(vm) < 0)
         return -1;
@@ -15515,8 +15580,8 @@ qemuDomainSnapshotCreateDiskActive(virQEMUDriverPtr driver,

     /* prepare a list of objects to use in the vm definition so that we don't
      * have to roll back later */
-    if (qemuDomainSnapshotDiskDataCollect(driver, vm, snap, reuse,
-                                          &diskdata, &ndiskdata) < 0)
+    if (qemuDomainSnapshotDiskDataCollect(driver, vm, snap, cfg, reuse, blockdev,
+                                          asyncJob, &diskdata, &ndiskdata) < 0)
         goto cleanup;

     /* check whether there's anything to do */
@@ -15530,11 +15595,18 @@ qemuDomainSnapshotCreateDiskActive(virQEMUDriverPtr driver,
       * VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL with a valid file name and
       * qcow2 format.  */
     for (i = 0; i < ndiskdata; i++) {
-        if (qemuBlockSnapshotAddLegacy(actions,
-                                       diskdata[i].disk,
-                                       diskdata[i].src,
-                                       reuse) < 0)
-            goto cleanup;
+        if (blockdev) {
+            if (qemuBlockSnapshotAddBlockdev(actions,
+                                             diskdata[i].disk,
+                                             diskdata[i].src))
+                goto cleanup;
+        } else {
+            if (qemuBlockSnapshotAddLegacy(actions,
+                                           diskdata[i].disk,
+                                           diskdata[i].src,
+                                           reuse) < 0)
+                goto cleanup;
+        }
     }

     if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
@@ -15551,7 +15623,7 @@ qemuDomainSnapshotCreateDiskActive(virQEMUDriverPtr driver,
         virDomainAuditDisk(vm, dd->disk->src, dd->src, "snapshot", rc >= 0);

         if (rc == 0)
-            qemuDomainSnapshotUpdateDiskSources(driver, vm, dd);
+            qemuDomainSnapshotUpdateDiskSources(driver, vm, dd, blockdev);
     }

     if (rc < 0)
@@ -15583,7 +15655,7 @@ qemuDomainSnapshotCreateDiskActive(virQEMUDriverPtr driver,
                                            vm->newDef) < 0))
         ret = -1;

-    qemuDomainSnapshotDiskDataCleanup(diskdata, ndiskdata, driver, vm);
+    qemuDomainSnapshotDiskDataCleanup(diskdata, ndiskdata, driver, vm, asyncJob);
     virErrorRestore(&orig_err);

     return ret;
-- 
2.21.0




More information about the libvir-list mailing list