Blame SOURCES/kvm-qemu-img-Add-skip-broken-bitmaps-for-convert-bitmaps.patch

a83cc2
From c5a2313ba173568087d78f76cc0258e7a353830b Mon Sep 17 00:00:00 2001
a83cc2
From: Eric Blake <eblake@redhat.com>
a83cc2
Date: Fri, 6 Aug 2021 15:07:49 -0400
a83cc2
Subject: [PATCH 26/39] qemu-img: Add --skip-broken-bitmaps for 'convert
a83cc2
 --bitmaps'
a83cc2
MIME-Version: 1.0
a83cc2
Content-Type: text/plain; charset=UTF-8
a83cc2
Content-Transfer-Encoding: 8bit
a83cc2
a83cc2
RH-Author: Miroslav Rezanina <mrezanin@redhat.com>
a83cc2
RH-MergeRequest: 35: Synchronize with RHEL-AV 8.5 release 28 to RHEL 9
a83cc2
RH-Commit: [3/4] 4b7203c66367c601f9710bbcd91bdbdd56f0f8bd (mrezanin/centos-src-qemu-kvm)
a83cc2
RH-Bugzilla: 1957194
a83cc2
RH-Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>
a83cc2
a83cc2
The point of 'qemu-img convert --bitmaps' is to be a convenience for
a83cc2
actions that are already possible through a string of smaller
a83cc2
'qemu-img bitmap' sub-commands.  One situation not accounted for
a83cc2
already is that if a source image contains an inconsistent bitmap (for
a83cc2
example, because a qemu process died abruptly before flushing bitmap
a83cc2
state), the user MUST delete those inconsistent bitmaps before
a83cc2
anything else useful can be done with the image.
a83cc2
a83cc2
We don't want to delete inconsistent bitmaps by default: although a
a83cc2
corrupt bitmap is only a loss of optimization rather than a corruption
a83cc2
of user-visible data, it is still nice to require the user to opt in
a83cc2
to the fact that they are aware of the loss of the bitmap.  Still,
a83cc2
requiring the user to check 'qemu-img info' to see whether bitmaps are
a83cc2
consistent, then use 'qemu-img bitmap --remove' to remove offenders,
a83cc2
all before using 'qemu-img convert', is a lot more work than just
a83cc2
adding a knob 'qemu-img convert --bitmaps --skip-broken-bitmaps' which
a83cc2
opts in to skipping the broken bitmaps.
a83cc2
a83cc2
After testing the new option, also demonstrate the way to manually fix
a83cc2
things (either deleting bad bitmaps, or re-creating them as empty) so
a83cc2
that it is possible to convert without the option.
a83cc2
a83cc2
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1946084
a83cc2
Signed-off-by: Eric Blake <eblake@redhat.com>
a83cc2
Message-Id: <20210709153951.2801666-4-eblake@redhat.com>
a83cc2
[eblake: warning message tweak, test enhancements]
a83cc2
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
a83cc2
(cherry picked from commit 955171e4417bf39edb5503e694501e082a757731)
a83cc2
Signed-off-by: Eric Blake <eblake@redhat.com>
a83cc2
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
a83cc2
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
a83cc2
---
a83cc2
 docs/tools/qemu-img.rst                       |  8 ++++-
a83cc2
 qemu-img.c                                    | 29 +++++++++++----
a83cc2
 tests/qemu-iotests/tests/qemu-img-bitmaps     | 16 ++++++++-
a83cc2
 tests/qemu-iotests/tests/qemu-img-bitmaps.out | 35 ++++++++++++++++++-
a83cc2
 4 files changed, 79 insertions(+), 9 deletions(-)
a83cc2
a83cc2
diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
a83cc2
index c9efcfaefc..3df6277d6a 100644
a83cc2
--- a/docs/tools/qemu-img.rst
a83cc2
+++ b/docs/tools/qemu-img.rst
a83cc2
@@ -414,7 +414,7 @@ Command description:
a83cc2
   4
a83cc2
     Error on reading data
a83cc2
 
a83cc2
-.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-r RATE_LIMIT] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME
a83cc2
+.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps [--skip-broken-bitmaps]] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-r RATE_LIMIT] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME
a83cc2
 
a83cc2
   Convert the disk image *FILENAME* or a snapshot *SNAPSHOT_PARAM*
a83cc2
   to disk image *OUTPUT_FILENAME* using format *OUTPUT_FMT*. It can
a83cc2
@@ -456,6 +456,12 @@ Command description:
a83cc2
   *NUM_COROUTINES* specifies how many coroutines work in parallel during
a83cc2
   the convert process (defaults to 8).
a83cc2
 
a83cc2
+  Use of ``--bitmaps`` requests that any persistent bitmaps present in
a83cc2
+  the original are also copied to the destination.  If any bitmap is
a83cc2
+  inconsistent in the source, the conversion will fail unless
a83cc2
+  ``--skip-broken-bitmaps`` is also specified to copy only the
a83cc2
+  consistent bitmaps.
a83cc2
+
a83cc2
 .. option:: create [--object OBJECTDEF] [-q] [-f FMT] [-b BACKING_FILE] [-F BACKING_FMT] [-u] [-o OPTIONS] FILENAME [SIZE]
a83cc2
 
a83cc2
   Create the new disk image *FILENAME* of size *SIZE* and format
a83cc2
diff --git a/qemu-img.c b/qemu-img.c
a83cc2
index 7684684bfa..75bab32416 100644
a83cc2
--- a/qemu-img.c
a83cc2
+++ b/qemu-img.c
a83cc2
@@ -82,6 +82,7 @@ enum {
a83cc2
     OPTION_MERGE = 274,
a83cc2
     OPTION_BITMAPS = 275,
a83cc2
     OPTION_FORCE = 276,
a83cc2
+    OPTION_SKIP_BROKEN = 277,
a83cc2
 };
a83cc2
 
a83cc2
 typedef enum OutputFormat {
a83cc2
@@ -2099,7 +2100,7 @@ static int convert_do_copy(ImgConvertState *s)
a83cc2
 }
a83cc2
 
a83cc2
 /* Check that bitmaps can be copied, or output an error */
a83cc2
-static int convert_check_bitmaps(BlockDriverState *src)
a83cc2
+static int convert_check_bitmaps(BlockDriverState *src, bool skip_broken)
a83cc2
 {
a83cc2
     BdrvDirtyBitmap *bm;
a83cc2
 
a83cc2
@@ -2111,17 +2112,19 @@ static int convert_check_bitmaps(BlockDriverState *src)
a83cc2
         if (!bdrv_dirty_bitmap_get_persistence(bm)) {
a83cc2
             continue;
a83cc2
         }
a83cc2
-        if (bdrv_dirty_bitmap_inconsistent(bm)) {
a83cc2
+        if (!skip_broken && bdrv_dirty_bitmap_inconsistent(bm)) {
a83cc2
             error_report("Cannot copy inconsistent bitmap '%s'",
a83cc2
                          bdrv_dirty_bitmap_name(bm));
a83cc2
-            error_printf("Try 'qemu-img bitmap --remove' to delete it\n");
a83cc2
+            error_printf("Try --skip-broken-bitmaps, or "
a83cc2
+                         "use 'qemu-img bitmap --remove' to delete it\n");
a83cc2
             return -1;
a83cc2
         }
a83cc2
     }
a83cc2
     return 0;
a83cc2
 }
a83cc2
 
a83cc2
-static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst)
a83cc2
+static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst,
a83cc2
+                                bool skip_broken)
a83cc2
 {
a83cc2
     BdrvDirtyBitmap *bm;
a83cc2
     Error *err = NULL;
a83cc2
@@ -2133,6 +2136,10 @@ static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst)
a83cc2
             continue;
a83cc2
         }
a83cc2
         name = bdrv_dirty_bitmap_name(bm);
a83cc2
+        if (skip_broken && bdrv_dirty_bitmap_inconsistent(bm)) {
a83cc2
+            warn_report("Skipping inconsistent bitmap '%s'", name);
a83cc2
+            continue;
a83cc2
+        }
a83cc2
         qmp_block_dirty_bitmap_add(dst->node_name, name,
a83cc2
                                    true, bdrv_dirty_bitmap_granularity(bm),
a83cc2
                                    true, true,
a83cc2
@@ -2188,6 +2195,7 @@ static int img_convert(int argc, char **argv)
a83cc2
     bool force_share = false;
a83cc2
     bool explict_min_sparse = false;
a83cc2
     bool bitmaps = false;
a83cc2
+    bool skip_broken = false;
a83cc2
     int64_t rate_limit = 0;
a83cc2
 
a83cc2
     ImgConvertState s = (ImgConvertState) {
a83cc2
@@ -2209,6 +2217,7 @@ static int img_convert(int argc, char **argv)
a83cc2
             {"salvage", no_argument, 0, OPTION_SALVAGE},
a83cc2
             {"target-is-zero", no_argument, 0, OPTION_TARGET_IS_ZERO},
a83cc2
             {"bitmaps", no_argument, 0, OPTION_BITMAPS},
a83cc2
+            {"skip-broken-bitmaps", no_argument, 0, OPTION_SKIP_BROKEN},
a83cc2
             {0, 0, 0, 0}
a83cc2
         };
a83cc2
         c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WUr:",
a83cc2
@@ -2337,6 +2346,9 @@ static int img_convert(int argc, char **argv)
a83cc2
         case OPTION_BITMAPS:
a83cc2
             bitmaps = true;
a83cc2
             break;
a83cc2
+        case OPTION_SKIP_BROKEN:
a83cc2
+            skip_broken = true;
a83cc2
+            break;
a83cc2
         }
a83cc2
     }
a83cc2
 
a83cc2
@@ -2344,6 +2356,11 @@ static int img_convert(int argc, char **argv)
a83cc2
         out_fmt = "raw";
a83cc2
     }
a83cc2
 
a83cc2
+    if (skip_broken && !bitmaps) {
a83cc2
+        error_report("Use of --skip-broken-bitmaps requires --bitmaps");
a83cc2
+        goto fail_getopt;
a83cc2
+    }
a83cc2
+
a83cc2
     if (s.compressed && s.copy_range) {
a83cc2
         error_report("Cannot enable copy offloading when -c is used");
a83cc2
         goto fail_getopt;
a83cc2
@@ -2573,7 +2590,7 @@ static int img_convert(int argc, char **argv)
a83cc2
             ret = -1;
a83cc2
             goto out;
a83cc2
         }
a83cc2
-        ret = convert_check_bitmaps(blk_bs(s.src[0]));
a83cc2
+        ret = convert_check_bitmaps(blk_bs(s.src[0]), skip_broken);
a83cc2
         if (ret < 0) {
a83cc2
             goto out;
a83cc2
         }
a83cc2
@@ -2698,7 +2715,7 @@ static int img_convert(int argc, char **argv)
a83cc2
 
a83cc2
     /* Now copy the bitmaps */
a83cc2
     if (bitmaps && ret == 0) {
a83cc2
-        ret = convert_copy_bitmaps(blk_bs(s.src[0]), out_bs);
a83cc2
+        ret = convert_copy_bitmaps(blk_bs(s.src[0]), out_bs, skip_broken);
a83cc2
     }
a83cc2
 
a83cc2
 out:
a83cc2
diff --git a/tests/qemu-iotests/tests/qemu-img-bitmaps b/tests/qemu-iotests/tests/qemu-img-bitmaps
a83cc2
index 09c3d395d1..7a3fe8c3d3 100755
a83cc2
--- a/tests/qemu-iotests/tests/qemu-img-bitmaps
a83cc2
+++ b/tests/qemu-iotests/tests/qemu-img-bitmaps
a83cc2
@@ -144,7 +144,21 @@ _img_info --format-specific | _filter_irrelevant_img_info
a83cc2
 echo
a83cc2
 $QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG" "$TEST_IMG.copy" &&
a83cc2
     echo "unexpected success"
a83cc2
-TEST_IMG=$TEST_IMG.copy _img_info --format-specific \
a83cc2
+TEST_IMG="$TEST_IMG.copy" _img_info --format-specific \
a83cc2
+    | _filter_irrelevant_img_info
a83cc2
+# Skipping the broken bitmaps works,...
a83cc2
+echo
a83cc2
+$QEMU_IMG convert --bitmaps --skip-broken-bitmaps \
a83cc2
+    -O qcow2 "$TEST_IMG" "$TEST_IMG.copy"
a83cc2
+TEST_IMG="$TEST_IMG.copy" _img_info --format-specific \
a83cc2
+    | _filter_irrelevant_img_info
a83cc2
+# ...as does removing them
a83cc2
+echo
a83cc2
+_rm_test_img "$TEST_IMG.copy"
a83cc2
+$QEMU_IMG bitmap --remove "$TEST_IMG" b0
a83cc2
+$QEMU_IMG bitmap --remove --add "$TEST_IMG" b2
a83cc2
+$QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG" "$TEST_IMG.copy"
a83cc2
+TEST_IMG="$TEST_IMG.copy" _img_info --format-specific \
a83cc2
     | _filter_irrelevant_img_info
a83cc2
 
a83cc2
 # success, all done
a83cc2
diff --git a/tests/qemu-iotests/tests/qemu-img-bitmaps.out b/tests/qemu-iotests/tests/qemu-img-bitmaps.out
a83cc2
index 1e32833bf1..7a7429e320 100644
a83cc2
--- a/tests/qemu-iotests/tests/qemu-img-bitmaps.out
a83cc2
+++ b/tests/qemu-iotests/tests/qemu-img-bitmaps.out
a83cc2
@@ -145,6 +145,39 @@ Format specific information:
a83cc2
     corrupt: false
a83cc2
 
a83cc2
 qemu-img: Cannot copy inconsistent bitmap 'b0'
a83cc2
-Try 'qemu-img bitmap --remove' to delete it
a83cc2
+Try --skip-broken-bitmaps, or use 'qemu-img bitmap --remove' to delete it
a83cc2
 qemu-img: Could not open 'TEST_DIR/t.IMGFMT.copy': Could not open 'TEST_DIR/t.IMGFMT.copy': No such file or directory
a83cc2
+
a83cc2
+qemu-img: warning: Skipping inconsistent bitmap 'b0'
a83cc2
+qemu-img: warning: Skipping inconsistent bitmap 'b2'
a83cc2
+image: TEST_DIR/t.IMGFMT.copy
a83cc2
+file format: IMGFMT
a83cc2
+virtual size: 10 MiB (10485760 bytes)
a83cc2
+cluster_size: 65536
a83cc2
+Format specific information:
a83cc2
+    bitmaps:
a83cc2
+        [0]:
a83cc2
+            flags:
a83cc2
+                [0]: auto
a83cc2
+            name: b4
a83cc2
+            granularity: 65536
a83cc2
+    corrupt: false
a83cc2
+
a83cc2
+image: TEST_DIR/t.IMGFMT.copy
a83cc2
+file format: IMGFMT
a83cc2
+virtual size: 10 MiB (10485760 bytes)
a83cc2
+cluster_size: 65536
a83cc2
+Format specific information:
a83cc2
+    bitmaps:
a83cc2
+        [0]:
a83cc2
+            flags:
a83cc2
+                [0]: auto
a83cc2
+            name: b4
a83cc2
+            granularity: 65536
a83cc2
+        [1]:
a83cc2
+            flags:
a83cc2
+                [0]: auto
a83cc2
+            name: b2
a83cc2
+            granularity: 65536
a83cc2
+    corrupt: false
a83cc2
 *** done
a83cc2
-- 
a83cc2
2.27.0
a83cc2