From: Peter Krempa <pkrempa@redhat.com>
Allow the hypervisor to assume that the user already passed a zeroed-out
image to optimize the copy. Implement the feature for the qemu driver.
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
---
include/libvirt/libvirt-domain.h | 7 +++++++
src/libvirt-domain.c | 4 ++++
src/qemu/qemu_driver.c | 16 +++++++++++++---
3 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index ccc2c87ea8..a0e0b84eb9 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5004,6 +5004,13 @@ typedef enum {
* Since: 8.0.0
*/
VIR_DOMAIN_BLOCK_COPY_SYNCHRONOUS_WRITES = 1 << 3,
+
+ /* Destination of the copy is zeroed (any read returns only 0x00 bytes) so
+ * the hypervisor may optimize out clearing of the target image.
+ *
+ * Since: 12.2.0 */
+ VIR_DOMAIN_BLOCK_COPY_TARGET_ZEROED = 1 << 4,
+
} virDomainBlockCopyFlags;
/**
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index 6b8783d57f..e1571cbda7 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -11261,6 +11261,10 @@ virDomainBlockRebase(virDomainPtr dom, const char *disk,
* the destination storage is slower. This may impact performance of writes
* while the blockjob is running.
*
+ * If @flags contains VIR_DOMAIN_BLOCK_COPY_TARGET_ZEROED the hypervisor may
+ * assume that the target image was already zeroed out (any read will return
+ * 0x00 bytes) and thus may skip this step.
+ *
* The @disk parameter is either an unambiguous source name of the
* block device (the <source file='...'/> sub-element, such as
* "/path/to/image"), or the device target shorthand (the
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0ba40e0665..42d0f46405 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -14285,13 +14285,15 @@ qemuDomainBlockCopyCommon(virDomainObj *vm,
virStorageSource *mirrorBacking = NULL;
g_autoptr(GHashTable) blockNamedNodeData = NULL;
bool syncWrites = !!(flags & VIR_DOMAIN_BLOCK_COPY_SYNCHRONOUS_WRITES);
+ bool targetIsZero = !!(flags & VIR_DOMAIN_BLOCK_COPY_TARGET_ZEROED);
int rc = 0;
/* Preliminaries: find the disk we are editing, sanity checks */
virCheckFlags(VIR_DOMAIN_BLOCK_COPY_SHALLOW |
VIR_DOMAIN_BLOCK_COPY_REUSE_EXT |
VIR_DOMAIN_BLOCK_COPY_TRANSIENT_JOB |
- VIR_DOMAIN_BLOCK_COPY_SYNCHRONOUS_WRITES, -1);
+ VIR_DOMAIN_BLOCK_COPY_SYNCHRONOUS_WRITES |
+ VIR_DOMAIN_BLOCK_COPY_TARGET_ZEROED, -1);
if (virStorageSourceIsRelative(mirror)) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
@@ -14327,6 +14329,13 @@ qemuDomainBlockCopyCommon(virDomainObj *vm,
goto endjob;
}
+ if (targetIsZero &&
+ !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV_MIRROR_TARGET_IS_ZERO)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("this qemu doesn't support 'VIR_DOMAIN_BLOCK_COPY_TARGET_ZEROED'"));
+ goto endjob;
+ }
+
if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN &&
virDomainDiskDefSourceLUNValidate(mirror) < 0)
goto endjob;
@@ -14535,7 +14544,7 @@ qemuDomainBlockCopyCommon(virDomainObj *vm,
qemuBlockStorageSourceGetEffectiveNodename(disk->src),
bandwidth,
granularity, buf_size, mirror_shallow,
- syncWrites, false);
+ syncWrites, targetIsZero);
virDomainAuditDisk(vm, NULL, mirror, "mirror", ret >= 0);
qemuDomainObjExitMonitor(vm);
@@ -14670,7 +14679,8 @@ qemuDomainBlockCopy(virDomainPtr dom,
virCheckFlags(VIR_DOMAIN_BLOCK_COPY_SHALLOW |
VIR_DOMAIN_BLOCK_COPY_REUSE_EXT |
VIR_DOMAIN_BLOCK_COPY_TRANSIENT_JOB |
- VIR_DOMAIN_BLOCK_COPY_SYNCHRONOUS_WRITES, -1);
+ VIR_DOMAIN_BLOCK_COPY_SYNCHRONOUS_WRITES |
+ VIR_DOMAIN_BLOCK_COPY_TARGET_ZEROED, -1);
if (virTypedParamsValidate(params, nparams,
VIR_DOMAIN_BLOCK_COPY_BANDWIDTH,
--
2.53.0