0a122b
From bd15ec3302904c9293bba0c1bac7225943b0e3fb Mon Sep 17 00:00:00 2001
0a122b
Message-Id: <bd15ec3302904c9293bba0c1bac7225943b0e3fb.1389014116.git.minovotn@redhat.com>
0a122b
In-Reply-To: <c8cc35838d42aa286242772d97e3a9be7bb786ba.1389014116.git.minovotn@redhat.com>
0a122b
References: <c8cc35838d42aa286242772d97e3a9be7bb786ba.1389014116.git.minovotn@redhat.com>
0a122b
From: Paolo Bonzini <pbonzini@redhat.com>
0a122b
Date: Mon, 9 Dec 2013 14:09:31 +0100
0a122b
Subject: [PATCH 43/50] qemu-img: add support for skipping zeroes in input
0a122b
 during convert
0a122b
0a122b
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
0a122b
Message-id: <1386598178-11845-46-git-send-email-pbonzini@redhat.com>
0a122b
Patchwork-id: 56082
0a122b
O-Subject: [RHEL 7.0 qemu-kvm PATCH 45/52] qemu-img: add support for skipping zeroes in input during convert
0a122b
Bugzilla: 1007815
0a122b
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
0a122b
RH-Acked-by: Fam Zheng <famz@redhat.com>
0a122b
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
0a122b
0a122b
From: Peter Lieven <pl@kamp.de>
0a122b
0a122b
we currently do not check if a sector is allocated during convert.
0a122b
This means if a sector is unallocated that we allocate a bounce
0a122b
buffer of zeroes, find out its zero later and do not write it
0a122b
in the best case. In the worst case this can lead to reading
0a122b
blocks from a raw device (like iSCSI) altough we could easily
0a122b
know via get_block_status that they are zero and simply skip them.
0a122b
0a122b
This patch also fixes the progress output not being at 100% after
0a122b
a successful conversion.
0a122b
0a122b
Signed-off-by: Peter Lieven <pl@kamp.de>
0a122b
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
0a122b
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
0a122b
(cherry picked from commit 13c28af87a5541a9b09a59502b876a1725fb502d)
0a122b
---
0a122b
 qemu-img.c | 80 +++++++++++++++++++++++++++++++++-----------------------------
0a122b
 1 file changed, 42 insertions(+), 38 deletions(-)
0a122b
0a122b
Signed-off-by: Michal Novotny <minovotn@redhat.com>
0a122b
---
0a122b
 qemu-img.c | 80 +++++++++++++++++++++++++++++++++-----------------------------
0a122b
 1 file changed, 42 insertions(+), 38 deletions(-)
0a122b
0a122b
diff --git a/qemu-img.c b/qemu-img.c
0a122b
index 3dacbec..a8e2d8c 100644
0a122b
--- a/qemu-img.c
0a122b
+++ b/qemu-img.c
0a122b
@@ -1123,13 +1123,15 @@ out3:
0a122b
 
0a122b
 static int img_convert(int argc, char **argv)
0a122b
 {
0a122b
-    int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size,
0a122b
+    int c, n, n1, bs_n, bs_i, compress, cluster_size,
0a122b
         cluster_sectors, skip_create;
0a122b
+    int64_t ret = 0;
0a122b
     int progress = 0, flags;
0a122b
     const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename;
0a122b
     BlockDriver *drv, *proto_drv;
0a122b
     BlockDriverState **bs = NULL, *out_bs = NULL;
0a122b
-    int64_t total_sectors, nb_sectors, sector_num, bs_offset;
0a122b
+    int64_t total_sectors, nb_sectors, sector_num, bs_offset,
0a122b
+            sector_num_next_status = 0;
0a122b
     uint64_t bs_sectors;
0a122b
     uint8_t * buf = NULL;
0a122b
     const uint8_t *buf1;
0a122b
@@ -1138,7 +1140,6 @@ static int img_convert(int argc, char **argv)
0a122b
     QEMUOptionParameter *out_baseimg_param;
0a122b
     char *options = NULL;
0a122b
     const char *snapshot_name = NULL;
0a122b
-    float local_progress = 0;
0a122b
     int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */
0a122b
     bool quiet = false;
0a122b
     Error *local_err = NULL;
0a122b
@@ -1401,10 +1402,6 @@ static int img_convert(int argc, char **argv)
0a122b
         sector_num = 0;
0a122b
 
0a122b
         nb_sectors = total_sectors;
0a122b
-        if (nb_sectors != 0) {
0a122b
-            local_progress = (float)100 /
0a122b
-                (nb_sectors / MIN(nb_sectors, cluster_sectors));
0a122b
-        }
0a122b
 
0a122b
         for(;;) {
0a122b
             int64_t bs_num;
0a122b
@@ -1462,7 +1459,7 @@ static int img_convert(int argc, char **argv)
0a122b
                 }
0a122b
             }
0a122b
             sector_num += n;
0a122b
-            qemu_progress_print(local_progress, 100);
0a122b
+            qemu_progress_print(100.0 * sector_num / total_sectors, 0);
0a122b
         }
0a122b
         /* signal EOF to align */
0a122b
         bdrv_write_compressed(out_bs, 0, NULL, 0);
0a122b
@@ -1479,21 +1476,13 @@ static int img_convert(int argc, char **argv)
0a122b
 
0a122b
         sector_num = 0; // total number of sectors converted so far
0a122b
         nb_sectors = total_sectors - sector_num;
0a122b
-        if (nb_sectors != 0) {
0a122b
-            local_progress = (float)100 /
0a122b
-                (nb_sectors / MIN(nb_sectors, IO_BUF_SIZE / 512));
0a122b
-        }
0a122b
 
0a122b
         for(;;) {
0a122b
             nb_sectors = total_sectors - sector_num;
0a122b
             if (nb_sectors <= 0) {
0a122b
+                ret = 0;
0a122b
                 break;
0a122b
             }
0a122b
-            if (nb_sectors >= (IO_BUF_SIZE / 512)) {
0a122b
-                n = (IO_BUF_SIZE / 512);
0a122b
-            } else {
0a122b
-                n = nb_sectors;
0a122b
-            }
0a122b
 
0a122b
             while (sector_num - bs_offset >= bs_sectors) {
0a122b
                 bs_i ++;
0a122b
@@ -1505,34 +1494,46 @@ static int img_convert(int argc, char **argv)
0a122b
                    sector_num, bs_i, bs_offset, bs_sectors); */
0a122b
             }
0a122b
 
0a122b
-            if (n > bs_offset + bs_sectors - sector_num) {
0a122b
-                n = bs_offset + bs_sectors - sector_num;
0a122b
-            }
0a122b
-
0a122b
-            /* If the output image is being created as a copy on write image,
0a122b
-               assume that sectors which are unallocated in the input image
0a122b
-               are present in both the output's and input's base images (no
0a122b
-               need to copy them). */
0a122b
-            if (out_baseimg) {
0a122b
-                ret = bdrv_is_allocated(bs[bs_i], sector_num - bs_offset,
0a122b
-                                        n, &n1;;
0a122b
+            if ((out_baseimg || has_zero_init) &&
0a122b
+                sector_num >= sector_num_next_status) {
0a122b
+                n = nb_sectors > INT_MAX ? INT_MAX : nb_sectors;
0a122b
+                ret = bdrv_get_block_status(bs[bs_i], sector_num - bs_offset,
0a122b
+                                            n, &n1;;
0a122b
                 if (ret < 0) {
0a122b
-                    error_report("error while reading metadata for sector "
0a122b
-                                 "%" PRId64 ": %s",
0a122b
-                                 sector_num - bs_offset, strerror(-ret));
0a122b
+                    error_report("error while reading block status of sector %"
0a122b
+                                 PRId64 ": %s", sector_num - bs_offset,
0a122b
+                                 strerror(-ret));
0a122b
                     goto out;
0a122b
                 }
0a122b
-                if (!ret) {
0a122b
+                /* If the output image is zero initialized, we are not working
0a122b
+                 * on a shared base and the input is zero we can skip the next
0a122b
+                 * n1 sectors */
0a122b
+                if (has_zero_init && !out_baseimg && (ret & BDRV_BLOCK_ZERO)) {
0a122b
                     sector_num += n1;
0a122b
                     continue;
0a122b
                 }
0a122b
-                /* The next 'n1' sectors are allocated in the input image. Copy
0a122b
-                   only those as they may be followed by unallocated sectors. */
0a122b
-                n = n1;
0a122b
-            } else {
0a122b
-                n1 = n;
0a122b
+                /* If the output image is being created as a copy on write
0a122b
+                 * image, assume that sectors which are unallocated in the
0a122b
+                 * input image are present in both the output's and input's
0a122b
+                 * base images (no need to copy them). */
0a122b
+                if (out_baseimg) {
0a122b
+                    if (!(ret & BDRV_BLOCK_DATA)) {
0a122b
+                        sector_num += n1;
0a122b
+                        continue;
0a122b
+                    }
0a122b
+                    /* The next 'n1' sectors are allocated in the input image.
0a122b
+                     * Copy only those as they may be followed by unallocated
0a122b
+                     * sectors. */
0a122b
+                    nb_sectors = n1;
0a122b
+                }
0a122b
+                /* avoid redundant callouts to get_block_status */
0a122b
+                sector_num_next_status = sector_num + n1;
0a122b
             }
0a122b
 
0a122b
+            n = MIN(nb_sectors, IO_BUF_SIZE / 512);
0a122b
+            n = MIN(n, bs_sectors - (sector_num - bs_offset));
0a122b
+            n1 = n;
0a122b
+
0a122b
             ret = bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n);
0a122b
             if (ret < 0) {
0a122b
                 error_report("error while reading sector %" PRId64 ": %s",
0a122b
@@ -1557,10 +1558,13 @@ static int img_convert(int argc, char **argv)
0a122b
                 n -= n1;
0a122b
                 buf1 += n1 * 512;
0a122b
             }
0a122b
-            qemu_progress_print(local_progress, 100);
0a122b
+            qemu_progress_print(100.0 * sector_num / total_sectors, 0);
0a122b
         }
0a122b
     }
0a122b
 out:
0a122b
+    if (!ret) {
0a122b
+        qemu_progress_print(100, 0);
0a122b
+    }
0a122b
     qemu_progress_end();
0a122b
     free_option_parameters(create_options);
0a122b
     free_option_parameters(param);
0a122b
-- 
0a122b
1.7.11.7
0a122b