26ba25
From 25b5ec4399eec0a03d91a103658a4fba4263ba4d Mon Sep 17 00:00:00 2001
26ba25
From: Max Reitz <mreitz@redhat.com>
26ba25
Date: Mon, 18 Jun 2018 18:04:50 +0200
26ba25
Subject: [PATCH 073/268] qemu-img: Special post-backing convert handling
26ba25
26ba25
RH-Author: Max Reitz <mreitz@redhat.com>
26ba25
Message-id: <20180618180451.23808-2-mreitz@redhat.com>
26ba25
Patchwork-id: 80795
26ba25
O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/2] qemu-img: Special post-backing convert handling
26ba25
Bugzilla: 1527898
26ba25
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
26ba25
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
26ba25
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
26ba25
26ba25
Currently, qemu-img convert writes zeroes when it reads zeroes.
26ba25
Sometimes it does not because the target is initialized to zeroes
26ba25
anyway, so we do not need to overwrite (and thus potentially allocate)
26ba25
it.  This is never the case for targets with backing files, though.  But
26ba25
even they may have an area that is initialized to zeroes, and that is
26ba25
the area past the end of the backing file (if that is shorter than the
26ba25
overlay).
26ba25
26ba25
So if the target format's unallocated blocks are zero and there is a gap
26ba25
between the target's backing file's end and the target's end, we do not
26ba25
have to explicitly write zeroes there.
26ba25
26ba25
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1527898
26ba25
Signed-off-by: Max Reitz <mreitz@redhat.com>
26ba25
Message-id: 20180501165750.19242-2-mreitz@redhat.com
26ba25
Reviewed-by: Eric Blake <eblake@redhat.com>
26ba25
Signed-off-by: Max Reitz <mreitz@redhat.com>
26ba25
(cherry picked from commit 351c8efff9ad809c822d55620df54d575d536f68)
26ba25
Signed-off-by: Max Reitz <mreitz@redhat.com>
26ba25
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
26ba25
---
26ba25
 qemu-img.c | 26 +++++++++++++++++++++++++-
26ba25
 1 file changed, 25 insertions(+), 1 deletion(-)
26ba25
26ba25
diff --git a/qemu-img.c b/qemu-img.c
26ba25
index 76d6e47..e2395b9 100644
26ba25
--- a/qemu-img.c
26ba25
+++ b/qemu-img.c
26ba25
@@ -1553,7 +1553,9 @@ typedef struct ImgConvertState {
26ba25
     BlockBackend *target;
26ba25
     bool has_zero_init;
26ba25
     bool compressed;
26ba25
+    bool unallocated_blocks_are_zero;
26ba25
     bool target_has_backing;
26ba25
+    int64_t target_backing_sectors; /* negative if unknown */
26ba25
     bool wr_in_order;
26ba25
     int min_sparse;
26ba25
     size_t cluster_sectors;
26ba25
@@ -1582,12 +1584,23 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
26ba25
 {
26ba25
     int64_t src_cur_offset;
26ba25
     int ret, n, src_cur;
26ba25
+    bool post_backing_zero = false;
26ba25
 
26ba25
     convert_select_part(s, sector_num, &src_cur, &src_cur_offset);
26ba25
 
26ba25
     assert(s->total_sectors > sector_num);
26ba25
     n = MIN(s->total_sectors - sector_num, BDRV_REQUEST_MAX_SECTORS);
26ba25
 
26ba25
+    if (s->target_backing_sectors >= 0) {
26ba25
+        if (sector_num >= s->target_backing_sectors) {
26ba25
+            post_backing_zero = s->unallocated_blocks_are_zero;
26ba25
+        } else if (sector_num + n > s->target_backing_sectors) {
26ba25
+            /* Split requests around target_backing_sectors (because
26ba25
+             * starting from there, zeros are handled differently) */
26ba25
+            n = s->target_backing_sectors - sector_num;
26ba25
+        }
26ba25
+    }
26ba25
+
26ba25
     if (s->sector_next_status <= sector_num) {
26ba25
         int64_t count = n * BDRV_SECTOR_SIZE;
26ba25
 
26ba25
@@ -1609,7 +1622,7 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
26ba25
         n = DIV_ROUND_UP(count, BDRV_SECTOR_SIZE);
26ba25
 
26ba25
         if (ret & BDRV_BLOCK_ZERO) {
26ba25
-            s->status = BLK_ZERO;
26ba25
+            s->status = post_backing_zero ? BLK_BACKING_FILE : BLK_ZERO;
26ba25
         } else if (ret & BDRV_BLOCK_DATA) {
26ba25
             s->status = BLK_DATA;
26ba25
         } else {
26ba25
@@ -2330,6 +2343,16 @@ static int img_convert(int argc, char **argv)
26ba25
         }
26ba25
     }
26ba25
 
26ba25
+    if (s.target_has_backing) {
26ba25
+        /* Errors are treated as "backing length unknown" (which means
26ba25
+         * s.target_backing_sectors has to be negative, which it will
26ba25
+         * be automatically).  The backing file length is used only
26ba25
+         * for optimizations, so such a case is not fatal. */
26ba25
+        s.target_backing_sectors = bdrv_nb_sectors(out_bs->backing->bs);
26ba25
+    } else {
26ba25
+        s.target_backing_sectors = -1;
26ba25
+    }
26ba25
+
26ba25
     ret = bdrv_get_info(out_bs, &bdi);
26ba25
     if (ret < 0) {
26ba25
         if (s.compressed) {
26ba25
@@ -2339,6 +2362,7 @@ static int img_convert(int argc, char **argv)
26ba25
     } else {
26ba25
         s.compressed = s.compressed || bdi.needs_compressed_writes;
26ba25
         s.cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE;
26ba25
+        s.unallocated_blocks_are_zero = bdi.unallocated_blocks_are_zero;
26ba25
     }
26ba25
 
26ba25
     ret = convert_do_copy(&s);
26ba25
-- 
26ba25
1.8.3.1
26ba25