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