- kvm-block-Expand-block-status-mode-from-bool-to-flags.patch [RHEL-88435 RHEL-88437] - kvm-file-posix-gluster-Handle-zero-block-status-hint-bet.patch [RHEL-88435 RHEL-88437] - kvm-block-Let-bdrv_co_is_zero_fast-consolidate-adjacent-.patch [RHEL-88435 RHEL-88437] - kvm-block-Add-new-bdrv_co_is_all_zeroes-function.patch [RHEL-88435 RHEL-88437] - kvm-iotests-Improve-iotest-194-to-mirror-data.patch [RHEL-88435 RHEL-88437] - kvm-mirror-Minor-refactoring.patch [RHEL-88435 RHEL-88437] - kvm-mirror-Pass-full-sync-mode-rather-than-bool-to-inter.patch [RHEL-88435 RHEL-88437] - kvm-mirror-Allow-QMP-override-to-declare-target-already-.patch [RHEL-88435 RHEL-88437] - kvm-mirror-Drop-redundant-zero_target-parameter.patch [RHEL-88435 RHEL-88437] - kvm-mirror-Skip-pre-zeroing-destination-if-it-is-already.patch [RHEL-88435 RHEL-88437] - kvm-mirror-Skip-writing-zeroes-when-target-is-already-ze.patch [RHEL-88435 RHEL-88437] - kvm-iotests-common.rc-add-disk_usage-function.patch [RHEL-88435 RHEL-88437] - kvm-tests-Add-iotest-mirror-sparse-for-recent-patches.patch [RHEL-88435 RHEL-88437] - kvm-mirror-Reduce-I-O-when-destination-is-detect-zeroes-.patch [RHEL-88435 RHEL-88437] - Resolves: RHEL-88435 (--migrate-disks-detect-zeroes doesn't take effect for disk migration [rhel-10.1]) - Resolves: RHEL-88437 (Disk size of target raw image is full allocated when doing mirror with default discard value [rhel-10.1])
144 lines
5.5 KiB
Diff
144 lines
5.5 KiB
Diff
From 659dd2d1f7b1facbf9c548468c1b50237f7aa8e4 Mon Sep 17 00:00:00 2001
|
|
From: Eric Blake <eblake@redhat.com>
|
|
Date: Fri, 9 May 2025 15:40:21 -0500
|
|
Subject: [PATCH 04/14] block: Add new bdrv_co_is_all_zeroes() function
|
|
|
|
RH-Author: Eric Blake <eblake@redhat.com>
|
|
RH-MergeRequest: 363: blockdev-mirror: More efficient handling of sparse mirrors
|
|
RH-Jira: RHEL-88435 RHEL-88437
|
|
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
RH-Commit: [4/14] 404590dbec0b1113872a7eb1bfe5af0450fe6a28 (ebblake/centos-qemu-kvm)
|
|
|
|
There are some optimizations that require knowing if an image starts
|
|
out as reading all zeroes, such as making blockdev-mirror faster by
|
|
skipping the copying of source zeroes to the destination. The
|
|
existing bdrv_co_is_zero_fast() is a good building block for answering
|
|
this question, but it tends to give an answer of 0 for a file we just
|
|
created via QMP 'blockdev-create' or similar (such as 'qemu-img create
|
|
-f raw'). Why? Because file-posix.c insists on allocating a tiny
|
|
header to any file rather than leaving it 100% sparse, due to some
|
|
filesystems that are unable to answer alignment probes on a hole. But
|
|
teaching file-posix.c to read the tiny header doesn't scale - the
|
|
problem of a small header is also visible when libvirt sets up an NBD
|
|
client to a just-created file on a migration destination host.
|
|
|
|
So, we need a wrapper function that handles a bit more complexity in a
|
|
common manner for all block devices - when the BDS is mostly a hole,
|
|
but has a small non-hole header, it is still worth the time to read
|
|
that header and check if it reads as all zeroes before giving up and
|
|
returning a pessimistic answer.
|
|
|
|
Signed-off-by: Eric Blake <eblake@redhat.com>
|
|
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
Message-ID: <20250509204341.3553601-19-eblake@redhat.com>
|
|
(cherry picked from commit 52726096707c5c8b90597c445de897fa64d56e73)
|
|
Jira: https://issues.redhat.com/browse/RHEL-88435
|
|
Jira: https://issues.redhat.com/browse/RHEL-88437
|
|
Signed-off-by: Eric Blake <eblake@redhat.com>
|
|
---
|
|
block/io.c | 62 ++++++++++++++++++++++++++++++++++++++++
|
|
include/block/block-io.h | 2 ++
|
|
2 files changed, 64 insertions(+)
|
|
|
|
diff --git a/block/io.c b/block/io.c
|
|
index 64f4b1d22a..b6fc07e1dc 100644
|
|
--- a/block/io.c
|
|
+++ b/block/io.c
|
|
@@ -38,10 +38,14 @@
|
|
#include "qemu/error-report.h"
|
|
#include "qemu/main-loop.h"
|
|
#include "system/replay.h"
|
|
+#include "qemu/units.h"
|
|
|
|
/* Maximum bounce buffer for copy-on-read and write zeroes, in bytes */
|
|
#define MAX_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS)
|
|
|
|
+/* Maximum read size for checking if data reads as zero, in bytes */
|
|
+#define MAX_ZERO_CHECK_BUFFER (128 * KiB)
|
|
+
|
|
static void coroutine_fn GRAPH_RDLOCK
|
|
bdrv_parent_cb_resize(BlockDriverState *bs);
|
|
|
|
@@ -2778,6 +2782,64 @@ int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset,
|
|
return 1;
|
|
}
|
|
|
|
+/*
|
|
+ * Check @bs (and its backing chain) to see if the entire image is known
|
|
+ * to read as zeroes.
|
|
+ * Return 1 if that is the case, 0 otherwise and -errno on error.
|
|
+ * This test is meant to be fast rather than accurate so returning 0
|
|
+ * does not guarantee non-zero data; however, a return of 1 is reliable,
|
|
+ * and this function can report 1 in more cases than bdrv_co_is_zero_fast.
|
|
+ */
|
|
+int coroutine_fn bdrv_co_is_all_zeroes(BlockDriverState *bs)
|
|
+{
|
|
+ int ret;
|
|
+ int64_t pnum, bytes;
|
|
+ char *buf;
|
|
+ QEMUIOVector local_qiov;
|
|
+ IO_CODE();
|
|
+
|
|
+ bytes = bdrv_co_getlength(bs);
|
|
+ if (bytes < 0) {
|
|
+ return bytes;
|
|
+ }
|
|
+
|
|
+ /* First probe - see if the entire image reads as zero */
|
|
+ ret = bdrv_co_common_block_status_above(bs, NULL, false, BDRV_WANT_ZERO,
|
|
+ 0, bytes, &pnum, NULL, NULL,
|
|
+ NULL);
|
|
+ if (ret < 0) {
|
|
+ return ret;
|
|
+ }
|
|
+ if (ret & BDRV_BLOCK_ZERO) {
|
|
+ return bdrv_co_is_zero_fast(bs, pnum, bytes - pnum);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Because of the way 'blockdev-create' works, raw files tend to
|
|
+ * be created with a non-sparse region at the front to make
|
|
+ * alignment probing easier. If the block starts with only a
|
|
+ * small allocated region, it is still worth the effort to see if
|
|
+ * the rest of the image is still sparse, coupled with manually
|
|
+ * reading the first region to see if it reads zero after all.
|
|
+ */
|
|
+ if (pnum > MAX_ZERO_CHECK_BUFFER) {
|
|
+ return 0;
|
|
+ }
|
|
+ ret = bdrv_co_is_zero_fast(bs, pnum, bytes - pnum);
|
|
+ if (ret <= 0) {
|
|
+ return ret;
|
|
+ }
|
|
+ /* Only the head of the image is unknown, and it's small. Read it. */
|
|
+ buf = qemu_blockalign(bs, pnum);
|
|
+ qemu_iovec_init_buf(&local_qiov, buf, pnum);
|
|
+ ret = bdrv_driver_preadv(bs, 0, pnum, &local_qiov, 0, 0);
|
|
+ if (ret >= 0) {
|
|
+ ret = buffer_is_zero(buf, pnum);
|
|
+ }
|
|
+ qemu_vfree(buf);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset,
|
|
int64_t bytes, int64_t *pnum)
|
|
{
|
|
diff --git a/include/block/block-io.h b/include/block/block-io.h
|
|
index b49e0537dd..b99cc98d26 100644
|
|
--- a/include/block/block-io.h
|
|
+++ b/include/block/block-io.h
|
|
@@ -161,6 +161,8 @@ bdrv_is_allocated_above(BlockDriverState *bs, BlockDriverState *base,
|
|
|
|
int coroutine_fn GRAPH_RDLOCK
|
|
bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, int64_t bytes);
|
|
+int coroutine_fn GRAPH_RDLOCK
|
|
+bdrv_co_is_all_zeroes(BlockDriverState *bs);
|
|
|
|
int GRAPH_RDLOCK
|
|
bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
|
|
--
|
|
2.39.3
|
|
|