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