Blame SOURCES/libvirt-qemu-blockcopy-Allow-late-opening-of-the-backing-chain-of-a-shallow-copy.patch

fbe740
From 7e60e728bc225b3499a3d1fad6b56d0ce8c40908 Mon Sep 17 00:00:00 2001
fbe740
Message-Id: <7e60e728bc225b3499a3d1fad6b56d0ce8c40908@dist-git>
fbe740
From: Peter Krempa <pkrempa@redhat.com>
fbe740
Date: Mon, 16 Mar 2020 22:11:39 +0100
fbe740
Subject: [PATCH] qemu: blockcopy: Allow late opening of the backing chain of a
fbe740
 shallow copy
fbe740
MIME-Version: 1.0
fbe740
Content-Type: text/plain; charset=UTF-8
fbe740
Content-Transfer-Encoding: 8bit
fbe740
fbe740
oVirt used a quirk in the pre-blockdev semantics of drive-mirror which
fbe740
opened the backing chain of the mirror destination only once
fbe740
'block-job-complete' was called.
fbe740
fbe740
Our introduction of blockdev made qemu open the backing chain images
fbe740
right at the start of the job. This broke oVirt's usage of this API
fbe740
because they copy the data into the backing chain during the time the
fbe740
block copy job is running.
fbe740
fbe740
Re-introduce late open of the backing chain if qemu allows us to use
fbe740
blockdev-snapshot on write-only nodes as it can be used to install the
fbe740
backing chain even for an existing image now.
fbe740
fbe740
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
fbe740
Reviewed-by: Eric Blake <eblake@redhat.com>
fbe740
(cherry picked from commit cc7868a8b3cfa4a0062936c23e82e4a31923f724)
fbe740
fbe740
https://bugzilla.redhat.com/show_bug.cgi?id=1803092
fbe740
Message-Id: <d37e660b9610d7a1cc42892ff3305cb477a8f98a.1584391726.git.pkrempa@redhat.com>
fbe740
Reviewed-by: Ján Tomko <jtomko@redhat.com>
fbe740
---
fbe740
 src/qemu/qemu_driver.c | 57 +++++++++++++++++++++++++++++++++++++++---
fbe740
 1 file changed, 53 insertions(+), 4 deletions(-)
fbe740
fbe740
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
fbe740
index 5a4e979907..441bb02b6b 100644
fbe740
--- a/src/qemu/qemu_driver.c
fbe740
+++ b/src/qemu/qemu_driver.c
fbe740
@@ -17556,10 +17556,12 @@ qemuDomainBlockPivot(virQEMUDriverPtr driver,
fbe740
                      qemuBlockJobDataPtr job,
fbe740
                      virDomainDiskDefPtr disk)
fbe740
 {
fbe740
+    g_autoptr(qemuBlockStorageSourceChainData) chainattachdata = NULL;
fbe740
     int ret = -1;
fbe740
     qemuDomainObjPrivatePtr priv = vm->privateData;
fbe740
     bool blockdev = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV);
fbe740
     g_autoptr(virJSONValue) actions = NULL;
fbe740
+    g_autoptr(virJSONValue) reopenactions = NULL;
fbe740
 
fbe740
     if (job->state != QEMU_BLOCKJOB_STATE_READY) {
fbe740
         virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
fbe740
@@ -17590,6 +17592,7 @@ qemuDomainBlockPivot(virQEMUDriverPtr driver,
fbe740
         if (blockdev && !job->jobflagsmissing) {
fbe740
             g_autoptr(virHashTable) blockNamedNodeData = NULL;
fbe740
             bool shallow = job->jobflags & VIR_DOMAIN_BLOCK_COPY_SHALLOW;
fbe740
+            bool reuse = job->jobflags & VIR_DOMAIN_BLOCK_COPY_REUSE_EXT;
fbe740
 
fbe740
             if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_NONE)))
fbe740
                 return -1;
fbe740
@@ -17598,6 +17601,27 @@ qemuDomainBlockPivot(virQEMUDriverPtr driver,
fbe740
                                                 blockNamedNodeData,
fbe740
                                                 shallow, &actions) < 0)
fbe740
                 return -1;
fbe740
+
fbe740
+            /* Open and install the backing chain of 'mirror' late if we can use
fbe740
+             * blockdev-snapshot to do it. This is to appease oVirt that wants
fbe740
+             * to copy data into the backing chain while the top image is being
fbe740
+             * copied shallow */
fbe740
+            if (reuse && shallow &&
fbe740
+                virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV_SNAPSHOT_ALLOW_WRITE_ONLY) &&
fbe740
+                virStorageSourceHasBacking(disk->mirror)) {
fbe740
+
fbe740
+                if (!(chainattachdata = qemuBuildStorageSourceChainAttachPrepareBlockdev(disk->mirror->backingStore,
fbe740
+                                                                                         priv->qemuCaps)))
fbe740
+                    return -1;
fbe740
+
fbe740
+                reopenactions = virJSONValueNewArray();
fbe740
+
fbe740
+                if (qemuMonitorTransactionSnapshotBlockdev(reopenactions,
fbe740
+                                                           disk->mirror->backingStore->nodeformat,
fbe740
+                                                           disk->mirror->nodeformat))
fbe740
+                    return -1;
fbe740
+            }
fbe740
+
fbe740
         }
fbe740
         break;
fbe740
 
fbe740
@@ -17609,7 +17633,15 @@ qemuDomainBlockPivot(virQEMUDriverPtr driver,
fbe740
     if (blockdev) {
fbe740
         int rc = 0;
fbe740
 
fbe740
-        if (actions)
fbe740
+        if (chainattachdata) {
fbe740
+            if ((rc = qemuBlockStorageSourceChainAttach(priv->mon, chainattachdata)) == 0) {
fbe740
+                /* install backing images on success, or unplug them on failure */
fbe740
+                if ((rc = qemuMonitorTransaction(priv->mon, &reopenactions)) != 0)
fbe740
+                    qemuBlockStorageSourceChainDetach(priv->mon, chainattachdata);
fbe740
+            }
fbe740
+        }
fbe740
+
fbe740
+        if (actions && rc == 0)
fbe740
             rc = qemuMonitorTransaction(priv->mon, &actions);
fbe740
 
fbe740
         if (rc == 0)
fbe740
@@ -18354,9 +18386,26 @@ qemuDomainBlockCopyCommon(virDomainObjPtr vm,
fbe740
 
fbe740
     if (blockdev) {
fbe740
         if (mirror_reuse) {
fbe740
-            if (!(data = qemuBuildStorageSourceChainAttachPrepareBlockdev(mirror,
fbe740
-                                                                          priv->qemuCaps)))
fbe740
-                goto endjob;
fbe740
+            /* oVirt depended on late-backing-chain-opening semantics the old
fbe740
+             * qemu command had to copy the backing chain data while the top
fbe740
+             * level is being copied. To restore this semantics if
fbe740
+             * blockdev-reopen is supported defer opening of the backing chain
fbe740
+             * of 'mirror' to the pivot step */
fbe740
+            if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV_SNAPSHOT_ALLOW_WRITE_ONLY)) {
fbe740
+                g_autoptr(virStorageSource) terminator = virStorageSourceNew();
fbe740
+
fbe740
+                if (!terminator)
fbe740
+                    goto endjob;
fbe740
+
fbe740
+                if (!(data = qemuBuildStorageSourceChainAttachPrepareBlockdevTop(mirror,
fbe740
+                                                                                 terminator,
fbe740
+                                                                                 priv->qemuCaps)))
fbe740
+                    goto endjob;
fbe740
+            } else {
fbe740
+                if (!(data = qemuBuildStorageSourceChainAttachPrepareBlockdev(mirror,
fbe740
+                                                                              priv->qemuCaps)))
fbe740
+                    goto endjob;
fbe740
+            }
fbe740
         } else {
fbe740
             if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_NONE)))
fbe740
                 goto endjob;
fbe740
-- 
fbe740
2.25.1
fbe740