oVirt used a quirk in the pre-blockdev semantics of drive-mirror which
opened the backing chain of the mirror destination only once
'block-job-complete' was called.
Our introduction of blockdev made qemu open the backing chain images
right at the start of the job. This broke oVirt's usage of this API
because they copy the data into the backing chain during the time the
block copy job is running.
Re-introduce late open of the backing chain if qemu supports
blockdev-reopen as we can use that command to install the backing chain
even for an existing image.
Signed-off-by: Peter Krempa <pkrempa(a)redhat.com>
---
src/qemu/qemu_driver.c | 53 +++++++++++++++++++++++++++++++++++++++---
1 file changed, 50 insertions(+), 3 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index c3215bccca..b746cd92d9 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -17229,6 +17229,7 @@ qemuDomainBlockPivot(virQEMUDriverPtr driver,
qemuBlockJobDataPtr job,
virDomainDiskDefPtr disk)
{
+ g_autoptr(qemuBlockStorageSourceChainData) chainattachdata = NULL;
int ret = -1;
qemuDomainObjPrivatePtr priv = vm->privateData;
bool blockdev = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV);
@@ -17263,6 +17264,7 @@ qemuDomainBlockPivot(virQEMUDriverPtr driver,
if (blockdev && !job->jobflagsmissing) {
g_autoptr(virHashTable) blockNamedNodeData = NULL;
bool shallow = job->jobflags & VIR_DOMAIN_BLOCK_COPY_SHALLOW;
+ bool reuse = job->jobflags & VIR_DOMAIN_BLOCK_COPY_REUSE_EXT;
if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm,
QEMU_ASYNC_JOB_NONE)))
return -1;
@@ -17271,6 +17273,17 @@ qemuDomainBlockPivot(virQEMUDriverPtr driver,
blockNamedNodeData,
shallow, &actions) < 0)
return -1;
+
+ /* Open and install the backing chain of 'mirror' late if we support
+ * blockdev-reopen. This is to appease oVirt that wants to copy
+ * data into the backing chain while the top image is being copied
+ * shallow */
+ if (reuse && shallow &&
+ virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV_REOPEN)) {
+ if (!(chainattachdata =
qemuBuildStorageSourceChainAttachPrepareBlockdev(disk->mirror->backingStore,
+
priv->qemuCaps)))
+ return -1;
+ }
}
break;
@@ -17278,6 +17291,23 @@ qemuDomainBlockPivot(virQEMUDriverPtr driver,
break;
}
+ if (chainattachdata) {
+ int rc;
+
+ qemuDomainObjEnterMonitor(driver, vm);
+ rc = qemuBlockStorageSourceChainAttach(priv->mon, chainattachdata);
+ if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
+ return -1;
+
+ if (qemuBlockReopenFormat(vm, disk->mirror, QEMU_ASYNC_JOB_NONE) < 0) {
+ qemuDomainObjEnterMonitor(driver, vm);
+ qemuBlockStorageSourceChainDetach(priv->mon, chainattachdata);
+ if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ return -1;
+ return -1;
+ }
+ }
+
qemuDomainObjEnterMonitor(driver, vm);
if (blockdev) {
int rc = 0;
@@ -18027,9 +18057,26 @@ qemuDomainBlockCopyCommon(virDomainObjPtr vm,
if (blockdev) {
if (mirror_reuse) {
- if (!(data = qemuBuildStorageSourceChainAttachPrepareBlockdev(mirror,
-
priv->qemuCaps)))
- goto endjob;
+ /* oVirt depended on late-backing-chain-opening semantics the old
+ * qemu command had to copy the backing chain data while the top
+ * level is being copied. To restore this semantics if
+ * blockdev-reopen is supported defer opening of the backing chain
+ * of 'mirror' to the pivot step */
+ if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV_REOPEN)) {
+ g_autoptr(virStorageSource) terminator = virStorageSourceNew();
+
+ if (!terminator)
+ goto endjob;
+
+ if (!(data = qemuBuildStorageSourceChainAttachPrepareBlockdevTop(mirror,
+
terminator,
+
priv->qemuCaps)))
+ goto endjob;
+ } else {
+ if (!(data = qemuBuildStorageSourceChainAttachPrepareBlockdev(mirror,
+
priv->qemuCaps)))
+ goto endjob;
+ }
} else {
if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm,
QEMU_ASYNC_JOB_NONE)))
goto endjob;
--
2.24.1