Wednesday, 23 January
2019
Wed, 23 Jan
'19
10:11 a.m.
Be more sensible when setting labels of the target of a
virDomainBlockCopy operation. Previously we'd relabel everything in case
it's a copy job even if there's no unlabelled backing chain. Since we
are also not sure whether the backing chain is shared we don't relabel
the chain on completion of the blockjob. This certainly won't play nice
with the image permission relabelling feature.
While this does not fix the case where the image is reused and has
backing chain it certainly sanitizes all the other cases. Later on it
will also allow to do the correct thing in cases where only one layer
was introduced.
Signed-off-by: Peter Krempa <pkrempa(a)redhat.com>
---
src/qemu/qemu_driver.c | 43 ++++++++++++++++++++---------------------
src/qemu/qemu_process.c | 22 +++++++++++++++++++++
2 files changed, 43 insertions(+), 22 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 79a767288e..2c2c0ce92e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -17170,26 +17170,6 @@ qemuDomainBlockPivot(virQEMUDriverPtr driver,
goto cleanup;
}
- /* For active commit, the mirror is part of the already labeled
- * chain. For blockcopy, we previously labeled only the top-level
- * image; but if the user is reusing an external image that
- * includes a backing file, the pivot may result in qemu needing
- * to open the entire backing chain, so we need to label the
- * entire chain. This action is safe even if the backing chain
- * has already been labeled; but only necessary when we know for
- * sure that there is a backing chain. */
- if (disk->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY) {
- if (qemuDomainDetermineDiskChain(driver, vm, disk, disk->mirror, true) <
0)
- goto cleanup;
-
- if (disk->mirror->format &&
- disk->mirror->format != VIR_STORAGE_FILE_RAW &&
- (qemuDomainNamespaceSetupDisk(vm, disk->mirror) < 0 ||
- qemuSetupImageChainCgroup(vm, disk->mirror) < 0 ||
- qemuSecuritySetImageLabel(driver, vm, disk->mirror, true) < 0))
- goto cleanup;
- }
-
/* Attempt the pivot. Record the attempt now, to prevent duplicate
* attempts; but the actual disk change will be made when emitting
* the event.
@@ -17836,9 +17816,28 @@ qemuDomainBlockCopyCommon(virDomainObjPtr vm,
keepParentLabel) < 0)
goto endjob;
- if (qemuDomainDiskChainElementPrepare(driver, vm, mirror, false, true) < 0) {
- qemuDomainDiskChainElementRevoke(driver, vm, mirror);
+ /* If reusing an external image that includes a backing file, the pivot may
+ * result in qemu needing to open the entire backing chain, so we need to
+ * label the full backing chain of the mirror instead of just the top image */
+ if (flags & VIR_DOMAIN_BLOCK_COPY_REUSE_EXT &&
+ mirror->format >= VIR_STORAGE_FILE_BACKING &&
+ qemuDomainDetermineDiskChain(driver, vm, disk, mirror, true) < 0)
goto endjob;
+
+ if (flags & VIR_DOMAIN_BLOCK_COPY_REUSE_EXT &&
+ virStorageSourceHasBacking(mirror)) {
+ /* note that we don't really know whether a part of the backing chain
+ * is shared so rolling this back is not as easy. Thus we do it only
+ * if there's a backing chain */
+ if (qemuDomainNamespaceSetupDisk(vm, mirror) < 0 ||
+ qemuSetupImageChainCgroup(vm, disk->mirror) < 0 ||
+ qemuSecuritySetImageLabel(driver, vm, disk->mirror, true) < 0)
+ goto endjob;
+ } else {
+ if (qemuDomainDiskChainElementPrepare(driver, vm, mirror, false, true) < 0) {
+ qemuDomainDiskChainElementRevoke(driver, vm, mirror);
+ goto endjob;
+ }
}
if (!(job = qemuBlockJobDiskNew(disk, QEMU_BLOCKJOB_TYPE_COPY, device)))
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index fb596d960f..c9e68397b6 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -7857,6 +7857,7 @@ qemuProcessRefreshLegacyBlockjob(void *payload,
virDomainDiskDefPtr disk;
qemuBlockJobDataPtr job;
qemuBlockJobType jobtype = info->type;
+ qemuDomainObjPrivatePtr priv = vm->privateData;
if (!(disk = qemuProcessFindDomainDiskByAliasOrQOM(vm, jobname, jobname))) {
VIR_DEBUG("could not find disk for block job '%s'", jobname);
@@ -7878,8 +7879,29 @@ qemuProcessRefreshLegacyBlockjob(void *payload,
disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_READY;
job->state = VIR_DOMAIN_BLOCK_JOB_READY;
}
+
+ /* Pre-blockdev block copy labelled the chain of the mirrored device
+ * just before pivoting. At that point it was no longer known whether
+ * it's even necessary (e.g. disk is being reused). This code fixes
+ * the labelling in case the job was started in a libvirt version
+ * which did not label the chain when the block copy is being started.
+ * Note that we can't do much on failure. */
+ if (disk->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY) {
+ if (qemuDomainDetermineDiskChain(priv->driver, vm, disk,
+ disk->mirror, true) < 0)
+ goto cleanup;
+
+ if (disk->mirror->format &&
+ disk->mirror->format != VIR_STORAGE_FILE_RAW &&
+ (qemuDomainNamespaceSetupDisk(vm, disk->mirror) < 0 ||
+ qemuSetupImageChainCgroup(vm, disk->mirror) < 0 ||
+ qemuSecuritySetImageLabel(priv->driver, vm, disk->mirror,
+ true) < 0))
+ goto cleanup;
+ }
}
+ cleanup:
qemuBlockJobStartupFinalize(job);
return 0;
--
2.20.1