summaryrefslogtreecommitdiffstats
path: root/qemu-img.c
diff options
context:
space:
mode:
authorEric Blake2021-07-21 17:53:48 +0200
committerEric Blake2021-07-21 21:14:41 +0200
commit955171e4417bf39edb5503e694501e082a757731 (patch)
tree89e724bf1cd142b1786fcc85675077c3138e4c23 /qemu-img.c
parentqemu-img: Fail fast on convert --bitmaps with inconsistent bitmap (diff)
downloadqemu-955171e4417bf39edb5503e694501e082a757731.tar.gz
qemu-955171e4417bf39edb5503e694501e082a757731.tar.xz
qemu-955171e4417bf39edb5503e694501e082a757731.zip
qemu-img: Add --skip-broken-bitmaps for 'convert --bitmaps'
The point of 'qemu-img convert --bitmaps' is to be a convenience for actions that are already possible through a string of smaller 'qemu-img bitmap' sub-commands. One situation not accounted for already is that if a source image contains an inconsistent bitmap (for example, because a qemu process died abruptly before flushing bitmap state), the user MUST delete those inconsistent bitmaps before anything else useful can be done with the image. We don't want to delete inconsistent bitmaps by default: although a corrupt bitmap is only a loss of optimization rather than a corruption of user-visible data, it is still nice to require the user to opt in to the fact that they are aware of the loss of the bitmap. Still, requiring the user to check 'qemu-img info' to see whether bitmaps are consistent, then use 'qemu-img bitmap --remove' to remove offenders, all before using 'qemu-img convert', is a lot more work than just adding a knob 'qemu-img convert --bitmaps --skip-broken-bitmaps' which opts in to skipping the broken bitmaps. After testing the new option, also demonstrate the way to manually fix things (either deleting bad bitmaps, or re-creating them as empty) so that it is possible to convert without the option. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1946084 Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <20210709153951.2801666-4-eblake@redhat.com> [eblake: warning message tweak, test enhancements] Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Diffstat (limited to 'qemu-img.c')
-rw-r--r--qemu-img.c29
1 files changed, 23 insertions, 6 deletions
diff --git a/qemu-img.c b/qemu-img.c
index c5496e82e0..908fd0cce5 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -82,6 +82,7 @@ enum {
OPTION_MERGE = 274,
OPTION_BITMAPS = 275,
OPTION_FORCE = 276,
+ OPTION_SKIP_BROKEN = 277,
};
typedef enum OutputFormat {
@@ -2102,7 +2103,7 @@ static int convert_do_copy(ImgConvertState *s)
}
/* Check that bitmaps can be copied, or output an error */
-static int convert_check_bitmaps(BlockDriverState *src)
+static int convert_check_bitmaps(BlockDriverState *src, bool skip_broken)
{
BdrvDirtyBitmap *bm;
@@ -2114,17 +2115,19 @@ static int convert_check_bitmaps(BlockDriverState *src)
if (!bdrv_dirty_bitmap_get_persistence(bm)) {
continue;
}
- if (bdrv_dirty_bitmap_inconsistent(bm)) {
+ if (!skip_broken && bdrv_dirty_bitmap_inconsistent(bm)) {
error_report("Cannot copy inconsistent bitmap '%s'",
bdrv_dirty_bitmap_name(bm));
- error_printf("Try 'qemu-img bitmap --remove' to delete it\n");
+ error_printf("Try --skip-broken-bitmaps, or "
+ "use 'qemu-img bitmap --remove' to delete it\n");
return -1;
}
}
return 0;
}
-static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst)
+static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst,
+ bool skip_broken)
{
BdrvDirtyBitmap *bm;
Error *err = NULL;
@@ -2136,6 +2139,10 @@ static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst)
continue;
}
name = bdrv_dirty_bitmap_name(bm);
+ if (skip_broken && bdrv_dirty_bitmap_inconsistent(bm)) {
+ warn_report("Skipping inconsistent bitmap '%s'", name);
+ continue;
+ }
qmp_block_dirty_bitmap_add(dst->node_name, name,
true, bdrv_dirty_bitmap_granularity(bm),
true, true,
@@ -2191,6 +2198,7 @@ static int img_convert(int argc, char **argv)
bool force_share = false;
bool explict_min_sparse = false;
bool bitmaps = false;
+ bool skip_broken = false;
int64_t rate_limit = 0;
ImgConvertState s = (ImgConvertState) {
@@ -2212,6 +2220,7 @@ static int img_convert(int argc, char **argv)
{"salvage", no_argument, 0, OPTION_SALVAGE},
{"target-is-zero", no_argument, 0, OPTION_TARGET_IS_ZERO},
{"bitmaps", no_argument, 0, OPTION_BITMAPS},
+ {"skip-broken-bitmaps", no_argument, 0, OPTION_SKIP_BROKEN},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WUr:",
@@ -2340,6 +2349,9 @@ static int img_convert(int argc, char **argv)
case OPTION_BITMAPS:
bitmaps = true;
break;
+ case OPTION_SKIP_BROKEN:
+ skip_broken = true;
+ break;
}
}
@@ -2347,6 +2359,11 @@ static int img_convert(int argc, char **argv)
out_fmt = "raw";
}
+ if (skip_broken && !bitmaps) {
+ error_report("Use of --skip-broken-bitmaps requires --bitmaps");
+ goto fail_getopt;
+ }
+
if (s.compressed && s.copy_range) {
error_report("Cannot enable copy offloading when -c is used");
goto fail_getopt;
@@ -2578,7 +2595,7 @@ static int img_convert(int argc, char **argv)
ret = -1;
goto out;
}
- ret = convert_check_bitmaps(blk_bs(s.src[0]));
+ ret = convert_check_bitmaps(blk_bs(s.src[0]), skip_broken);
if (ret < 0) {
goto out;
}
@@ -2703,7 +2720,7 @@ static int img_convert(int argc, char **argv)
/* Now copy the bitmaps */
if (bitmaps && ret == 0) {
- ret = convert_copy_bitmaps(blk_bs(s.src[0]), out_bs);
+ ret = convert_copy_bitmaps(blk_bs(s.src[0]), out_bs, skip_broken);
}
out: