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:
Peter Maydell 2021-07-22 09:33:03 +01:00
commit 423a4849db
5 changed files with 152 additions and 9 deletions

View file

@ -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;
}

View file

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

View file

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

View file

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

View file

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