block bitmaps patches for 2021-07-21
- fix 'qemu-img convert --bitmaps' handling of qcow2 files with inconsistent bitmaps -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEccLMIrHEYCkn0vOqp6FrSiUnQ2oFAmD4cnkACgkQp6FrSiUn Q2o4dQf+IogXgGLT6BgsLloAQuErlUrgz9RQ/Oj5iF7Jh5KpwvitIL6ThcjMlLoZ h8UCief1SvASMU4wlPGYoFKU3CeDRrMpIJadahxAALn0LHOStzKd133o8CvgMkV8 j6s3kSM17+Y/tHkvDPsWwRsTfiAKgPz70nQXR+ELcW3rEgVoHr/82e13e9CEAr93 3D4U++PpuGbRRKpEJxaz2uuFqZqsAGwTnvUrRDYunN6UhOtEMuIPcdTYpt4UDUmK qQyTjzqYMElMmwWDUpep9KSdIxVolyRxjSFWS40NLLnPUywY5NjLDkBk5KDH3vXm mA59hksXcekJ5v30FmJJL6N8/cYsEQ== =RfMA -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/ericb/tags/pull-bitmaps-2021-07-21' into staging block bitmaps patches for 2021-07-21 - fix 'qemu-img convert --bitmaps' handling of qcow2 files with inconsistent bitmaps # gpg: Signature made Wed 21 Jul 2021 20:16:09 BST # gpg: using RSA key 71C2CC22B1C4602927D2F3AAA7A16B4A2527436A # gpg: Good signature from "Eric Blake <eblake@redhat.com>" [full] # gpg: aka "Eric Blake (Free Software Programmer) <ebb9@byu.net>" [full] # gpg: aka "[jpeg image of size 6874]" [full] # Primary key fingerprint: 71C2 CC22 B1C4 6029 27D2 F3AA A7A1 6B4A 2527 436A * remotes/ericb/tags/pull-bitmaps-2021-07-21: qemu-img: Add --skip-broken-bitmaps for 'convert --bitmaps' qemu-img: Fail fast on convert --bitmaps with inconsistent bitmap iotests: Improve and rename test 291 to qemu-img-bitmap Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
423a4849db
@ -193,7 +193,7 @@ int bdrv_dirty_bitmap_check(const BdrvDirtyBitmap *bitmap, uint32_t flags,
|
||||
error_setg(errp, "Bitmap '%s' is inconsistent and cannot be used",
|
||||
bitmap->name);
|
||||
error_append_hint(errp, "Try block-dirty-bitmap-remove to delete"
|
||||
" this bitmap from disk");
|
||||
" this bitmap from disk\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -414,7 +414,7 @@ Command description:
|
||||
4
|
||||
Error on reading data
|
||||
|
||||
.. 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
|
||||
.. 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
|
||||
|
||||
Convert the disk image *FILENAME* or a snapshot *SNAPSHOT_PARAM*
|
||||
to disk image *OUTPUT_FILENAME* using format *OUTPUT_FMT*. It can
|
||||
@ -456,6 +456,12 @@ Command description:
|
||||
*NUM_COROUTINES* specifies how many coroutines work in parallel during
|
||||
the convert process (defaults to 8).
|
||||
|
||||
Use of ``--bitmaps`` requests that any persistent bitmaps present in
|
||||
the original are also copied to the destination. If any bitmap is
|
||||
inconsistent in the source, the conversion will fail unless
|
||||
``--skip-broken-bitmaps`` is also specified to copy only the
|
||||
consistent bitmaps.
|
||||
|
||||
.. option:: create [--object OBJECTDEF] [-q] [-f FMT] [-b BACKING_FILE] [-F BACKING_FMT] [-u] [-o OPTIONS] FILENAME [SIZE]
|
||||
|
||||
Create the new disk image *FILENAME* of size *SIZE* and format
|
||||
|
50
qemu-img.c
50
qemu-img.c
@ -82,6 +82,7 @@ enum {
|
||||
OPTION_MERGE = 274,
|
||||
OPTION_BITMAPS = 275,
|
||||
OPTION_FORCE = 276,
|
||||
OPTION_SKIP_BROKEN = 277,
|
||||
};
|
||||
|
||||
typedef enum OutputFormat {
|
||||
@ -2101,7 +2102,32 @@ static int convert_do_copy(ImgConvertState *s)
|
||||
return s->ret;
|
||||
}
|
||||
|
||||
static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst)
|
||||
/* Check that bitmaps can be copied, or output an error */
|
||||
static int convert_check_bitmaps(BlockDriverState *src, bool skip_broken)
|
||||
{
|
||||
BdrvDirtyBitmap *bm;
|
||||
|
||||
if (!bdrv_supports_persistent_dirty_bitmap(src)) {
|
||||
error_report("Source lacks bitmap support");
|
||||
return -1;
|
||||
}
|
||||
FOR_EACH_DIRTY_BITMAP(src, bm) {
|
||||
if (!bdrv_dirty_bitmap_get_persistence(bm)) {
|
||||
continue;
|
||||
}
|
||||
if (!skip_broken && bdrv_dirty_bitmap_inconsistent(bm)) {
|
||||
error_report("Cannot copy inconsistent bitmap '%s'",
|
||||
bdrv_dirty_bitmap_name(bm));
|
||||
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,
|
||||
bool skip_broken)
|
||||
{
|
||||
BdrvDirtyBitmap *bm;
|
||||
Error *err = NULL;
|
||||
@ -2113,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,
|
||||
@ -2127,6 +2157,7 @@ static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst)
|
||||
&err);
|
||||
if (err) {
|
||||
error_reportf_err(err, "Failed to populate bitmap %s: ", name);
|
||||
qmp_block_dirty_bitmap_remove(dst->node_name, name, NULL);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -2167,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) {
|
||||
@ -2188,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:",
|
||||
@ -2316,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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2323,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;
|
||||
@ -2554,9 +2595,8 @@ static int img_convert(int argc, char **argv)
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
if (!bdrv_supports_persistent_dirty_bitmap(blk_bs(s.src[0]))) {
|
||||
error_report("Source lacks bitmap support");
|
||||
ret = -1;
|
||||
ret = convert_check_bitmaps(blk_bs(s.src[0]), skip_broken);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@ -2680,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:
|
||||
|
@ -3,7 +3,7 @@
|
||||
#
|
||||
# Test qemu-img bitmap handling
|
||||
#
|
||||
# Copyright (C) 2018-2020 Red Hat, Inc.
|
||||
# Copyright (C) 2018-2021 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@ -27,11 +27,13 @@ status=1 # failure is the default!
|
||||
_cleanup()
|
||||
{
|
||||
_cleanup_test_img
|
||||
_rm_test_img "$TEST_IMG.copy"
|
||||
nbd_server_stop
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
cd ..
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
. ./common.nbd
|
||||
@ -129,6 +131,36 @@ $QEMU_IMG map --output=json --image-opts \
|
||||
|
||||
nbd_server_stop
|
||||
|
||||
echo
|
||||
echo "=== Check handling of inconsistent bitmap ==="
|
||||
echo
|
||||
|
||||
# Prepare image with corrupted bitmap
|
||||
$QEMU_IO -c abort "$TEST_IMG" 2>/dev/null
|
||||
$QEMU_IMG bitmap --add "$TEST_IMG" b4
|
||||
$QEMU_IMG bitmap --remove "$TEST_IMG" b1
|
||||
_img_info --format-specific | _filter_irrelevant_img_info
|
||||
# Proof that we fail fast if bitmaps can't be copied
|
||||
echo
|
||||
$QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG" "$TEST_IMG.copy" &&
|
||||
echo "unexpected success"
|
||||
TEST_IMG="$TEST_IMG.copy" _img_info --format-specific \
|
||||
| _filter_irrelevant_img_info
|
||||
# Skipping the broken bitmaps works,...
|
||||
echo
|
||||
$QEMU_IMG convert --bitmaps --skip-broken-bitmaps \
|
||||
-O qcow2 "$TEST_IMG" "$TEST_IMG.copy"
|
||||
TEST_IMG="$TEST_IMG.copy" _img_info --format-specific \
|
||||
| _filter_irrelevant_img_info
|
||||
# ...as does removing them
|
||||
echo
|
||||
_rm_test_img "$TEST_IMG.copy"
|
||||
$QEMU_IMG bitmap --remove "$TEST_IMG" b0
|
||||
$QEMU_IMG bitmap --remove --add "$TEST_IMG" b2
|
||||
$QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG" "$TEST_IMG.copy"
|
||||
TEST_IMG="$TEST_IMG.copy" _img_info --format-specific \
|
||||
| _filter_irrelevant_img_info
|
||||
|
||||
# success, all done
|
||||
echo '*** done'
|
||||
rm -f $seq.full
|
@ -1,4 +1,4 @@
|
||||
QA output created by 291
|
||||
QA output created by qemu-img-bitmaps
|
||||
|
||||
=== Initial image setup ===
|
||||
|
||||
@ -115,4 +115,69 @@ Format specific information:
|
||||
[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
|
||||
{ "start": 2097152, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false},
|
||||
{ "start": 3145728, "length": 7340032, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
|
||||
|
||||
=== Check handling of inconsistent bitmap ===
|
||||
|
||||
image: TEST_DIR/t.IMGFMT
|
||||
file format: IMGFMT
|
||||
virtual size: 10 MiB (10485760 bytes)
|
||||
cluster_size: 65536
|
||||
backing file: TEST_DIR/t.IMGFMT.base
|
||||
backing file format: IMGFMT
|
||||
Format specific information:
|
||||
bitmaps:
|
||||
[0]:
|
||||
flags:
|
||||
[0]: in-use
|
||||
[1]: auto
|
||||
name: b2
|
||||
granularity: 65536
|
||||
[1]:
|
||||
flags:
|
||||
[0]: in-use
|
||||
name: b0
|
||||
granularity: 65536
|
||||
[2]:
|
||||
flags:
|
||||
[0]: auto
|
||||
name: b4
|
||||
granularity: 65536
|
||||
corrupt: false
|
||||
|
||||
qemu-img: Cannot copy inconsistent bitmap 'b0'
|
||||
Try --skip-broken-bitmaps, or use 'qemu-img bitmap --remove' to delete it
|
||||
qemu-img: Could not open 'TEST_DIR/t.IMGFMT.copy': Could not open 'TEST_DIR/t.IMGFMT.copy': No such file or directory
|
||||
|
||||
qemu-img: warning: Skipping inconsistent bitmap 'b0'
|
||||
qemu-img: warning: Skipping inconsistent bitmap 'b2'
|
||||
image: TEST_DIR/t.IMGFMT.copy
|
||||
file format: IMGFMT
|
||||
virtual size: 10 MiB (10485760 bytes)
|
||||
cluster_size: 65536
|
||||
Format specific information:
|
||||
bitmaps:
|
||||
[0]:
|
||||
flags:
|
||||
[0]: auto
|
||||
name: b4
|
||||
granularity: 65536
|
||||
corrupt: false
|
||||
|
||||
image: TEST_DIR/t.IMGFMT.copy
|
||||
file format: IMGFMT
|
||||
virtual size: 10 MiB (10485760 bytes)
|
||||
cluster_size: 65536
|
||||
Format specific information:
|
||||
bitmaps:
|
||||
[0]:
|
||||
flags:
|
||||
[0]: auto
|
||||
name: b4
|
||||
granularity: 65536
|
||||
[1]:
|
||||
flags:
|
||||
[0]: auto
|
||||
name: b2
|
||||
granularity: 65536
|
||||
corrupt: false
|
||||
*** done
|
Loading…
Reference in New Issue
Block a user