aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2020-04-24 16:27:01 +0200
committerKevin Wolf <kwolf@redhat.com>2020-04-30 17:51:07 +0200
commiteb8a0cf3ba26611f3981f8f45ac6a868975a68cc (patch)
tree4b8711b089ae88ba8166f9881f83ac3ffb1092b5
parentbf03dede475e29a16f9188ea85a4d77cd3dcf2b7 (diff)
downloadqemu-eb8a0cf3ba26611f3981f8f45ac6a868975a68cc.zip
qemu-eb8a0cf3ba26611f3981f8f45ac6a868975a68cc.tar.gz
qemu-eb8a0cf3ba26611f3981f8f45ac6a868975a68cc.tar.bz2
qcow2: Forward ZERO_WRITE flag for full preallocation
The BDRV_REQ_ZERO_WRITE is currently implemented in a way that first the image is possibly preallocated and then the zero flag is added to all clusters. This means that a copy-on-write operation may be needed when writing to these clusters, despite having used preallocation, negating one of the major benefits of preallocation. Instead, try to forward the BDRV_REQ_ZERO_WRITE to the protocol driver, and if the protocol driver can ensure that the new area reads as zeros, we can skip setting the zero flag in the qcow2 layer. Unfortunately, the same approach doesn't work for metadata preallocation, so we'll still set the zero flag there. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com> Message-Id: <20200424142701.67053-1-kwolf@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
-rw-r--r--block/qcow2.c22
-rw-r--r--tests/qemu-iotests/274.out4
2 files changed, 21 insertions, 5 deletions
diff --git a/block/qcow2.c b/block/qcow2.c
index 98065d7..2ba0b17 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -4170,9 +4170,25 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
/* Allocate the data area */
new_file_size = allocation_start +
nb_new_data_clusters * s->cluster_size;
- /* Image file grows, so @exact does not matter */
- ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
- errp);
+ /*
+ * Image file grows, so @exact does not matter.
+ *
+ * If we need to zero out the new area, try first whether the protocol
+ * driver can already take care of this.
+ */
+ if (flags & BDRV_REQ_ZERO_WRITE) {
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc,
+ BDRV_REQ_ZERO_WRITE, NULL);
+ if (ret >= 0) {
+ flags &= ~BDRV_REQ_ZERO_WRITE;
+ }
+ } else {
+ ret = -1;
+ }
+ if (ret < 0) {
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
+ errp);
+ }
if (ret < 0) {
error_prepend(errp, "Failed to resize underlying file: ");
qcow2_free_clusters(bs, allocation_start,
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
index 1a796fd..9d6fdeb 100644
--- a/tests/qemu-iotests/274.out
+++ b/tests/qemu-iotests/274.out
@@ -187,7 +187,7 @@ read 65536/65536 bytes at offset 9437184
10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
-{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}]
+{ "start": 5242880, "length": 10485760, "depth": 0, "zero": false, "data": true, "offset": 327680}]
=== preallocation=full ===
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
@@ -206,7 +206,7 @@ read 65536/65536 bytes at offset 11534336
4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000)
[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false},
-{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}]
+{ "start": 8388608, "length": 4194304, "depth": 0, "zero": false, "data": true, "offset": 327680}]
=== preallocation=off ===
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16