Blame SOURCES/kvm-qcow2-Support-BDRV_REQ_ZERO_WRITE-for-truncate.patch

ddf19c
From 3e603e344b81b3ecfea6fb9589ba91f70a22139d Mon Sep 17 00:00:00 2001
ddf19c
From: Kevin Wolf <kwolf@redhat.com>
ddf19c
Date: Mon, 8 Jun 2020 15:01:33 +0100
ddf19c
Subject: [PATCH 05/17] qcow2: Support BDRV_REQ_ZERO_WRITE for truncate
ddf19c
ddf19c
RH-Author: Kevin Wolf <kwolf@redhat.com>
ddf19c
Message-id: <20200608150140.38218-5-kwolf@redhat.com>
ddf19c
Patchwork-id: 97449
ddf19c
O-Subject: [RHEL-AV-8.2.1 qemu-kvm PATCH 04/11] qcow2: Support BDRV_REQ_ZERO_WRITE for truncate
ddf19c
Bugzilla: 1780574
ddf19c
RH-Acked-by: Sergio Lopez Pascual <slp@redhat.com>
ddf19c
RH-Acked-by: Eric Blake <eblake@redhat.com>
ddf19c
RH-Acked-by: Max Reitz <mreitz@redhat.com>
ddf19c
ddf19c
If BDRV_REQ_ZERO_WRITE is set and we're extending the image, calling
ddf19c
qcow2_cluster_zeroize() with flags=0 does the right thing: It doesn't
ddf19c
undo any previous preallocation, but just adds the zero flag to all
ddf19c
relevant L2 entries. If an external data file is in use, a write_zeroes
ddf19c
request to the data file is made instead.
ddf19c
ddf19c
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
ddf19c
Message-Id: <20200424125448.63318-5-kwolf@redhat.com>
ddf19c
Reviewed-by: Eric Blake <eblake@redhat.com>
ddf19c
Reviewed-by: Max Reitz <mreitz@redhat.com>
ddf19c
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
ddf19c
(cherry picked from commit f01643fb8b47e8a70c04bbf45e0f12a9e5bc54de)
ddf19c
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
ddf19c
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
ddf19c
---
ddf19c
 block/qcow2-cluster.c |  2 +-
ddf19c
 block/qcow2.c         | 34 ++++++++++++++++++++++++++++++++++
ddf19c
 2 files changed, 35 insertions(+), 1 deletion(-)
ddf19c
ddf19c
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
ddf19c
index dc3c270..9d04f8d 100644
ddf19c
--- a/block/qcow2-cluster.c
ddf19c
+++ b/block/qcow2-cluster.c
ddf19c
@@ -1784,7 +1784,7 @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
ddf19c
     /* Caller must pass aligned values, except at image end */
ddf19c
     assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
ddf19c
     assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) ||
ddf19c
-           end_offset == bs->total_sectors << BDRV_SECTOR_BITS);
ddf19c
+           end_offset >= bs->total_sectors << BDRV_SECTOR_BITS);
ddf19c
 
ddf19c
     /* The zero flag is only supported by version 3 and newer */
ddf19c
     if (s->qcow_version < 3) {
ddf19c
diff --git a/block/qcow2.c b/block/qcow2.c
ddf19c
index 86aa74a..f3d6cb0 100644
ddf19c
--- a/block/qcow2.c
ddf19c
+++ b/block/qcow2.c
ddf19c
@@ -1726,6 +1726,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
ddf19c
     }
ddf19c
 
ddf19c
     bs->supported_zero_flags = header.version >= 3 ? BDRV_REQ_MAY_UNMAP : 0;
ddf19c
+    bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
ddf19c
 
ddf19c
     /* Repair image if dirty */
ddf19c
     if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only &&
ddf19c
@@ -4197,6 +4198,39 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
ddf19c
         g_assert_not_reached();
ddf19c
     }
ddf19c
 
ddf19c
+    if ((flags & BDRV_REQ_ZERO_WRITE) && offset > old_length) {
ddf19c
+        uint64_t zero_start = QEMU_ALIGN_UP(old_length, s->cluster_size);
ddf19c
+
ddf19c
+        /*
ddf19c
+         * Use zero clusters as much as we can. qcow2_cluster_zeroize()
ddf19c
+         * requires a cluster-aligned start. The end may be unaligned if it is
ddf19c
+         * at the end of the image (which it is here).
ddf19c
+         */
ddf19c
+        ret = qcow2_cluster_zeroize(bs, zero_start, offset - zero_start, 0);
ddf19c
+        if (ret < 0) {
ddf19c
+            error_setg_errno(errp, -ret, "Failed to zero out new clusters");
ddf19c
+            goto fail;
ddf19c
+        }
ddf19c
+
ddf19c
+        /* Write explicit zeros for the unaligned head */
ddf19c
+        if (zero_start > old_length) {
ddf19c
+            uint64_t len = zero_start - old_length;
ddf19c
+            uint8_t *buf = qemu_blockalign0(bs, len);
ddf19c
+            QEMUIOVector qiov;
ddf19c
+            qemu_iovec_init_buf(&qiov, buf, len);
ddf19c
+
ddf19c
+            qemu_co_mutex_unlock(&s->lock);
ddf19c
+            ret = qcow2_co_pwritev_part(bs, old_length, len, &qiov, 0, 0);
ddf19c
+            qemu_co_mutex_lock(&s->lock);
ddf19c
+
ddf19c
+            qemu_vfree(buf);
ddf19c
+            if (ret < 0) {
ddf19c
+                error_setg_errno(errp, -ret, "Failed to zero out the new area");
ddf19c
+                goto fail;
ddf19c
+            }
ddf19c
+        }
ddf19c
+    }
ddf19c
+
ddf19c
     if (prealloc != PREALLOC_MODE_OFF) {
ddf19c
         /* Flush metadata before actually changing the image size */
ddf19c
         ret = qcow2_write_caches(bs);
ddf19c
-- 
ddf19c
1.8.3.1
ddf19c