|
|
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 |
|