qemu/tests/qemu-iotests/tests/qemu-img-bitmaps
Eric Blake 955171e441 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>
2021-07-21 14:14:41 -05:00

167 lines
5.6 KiB
Bash
Executable file

#!/usr/bin/env bash
# group: rw quick
#
# Test qemu-img bitmap handling
#
# 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
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
seq="$(basename $0)"
echo "QA output created by $seq"
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
_supported_fmt qcow2
_supported_proto file fuse
_supported_os Linux
_require_command QEMU_NBD
# compat=0.10 does not support bitmaps
_unsupported_imgopts 'compat=0.10'
# Filter irrelevant format-specific information from the qemu-img info
# output (we only want the bitmaps, basically)
_filter_irrelevant_img_info()
{
grep -v -e 'compat' -e 'compression type' -e 'data file' -e 'extended l2' \
-e 'lazy refcounts' -e 'refcount bits'
}
echo
echo "=== Initial image setup ==="
echo
# Create backing image with one bitmap
TEST_IMG="$TEST_IMG.base" _make_test_img 10M
$QEMU_IMG bitmap --add -f $IMGFMT "$TEST_IMG.base" b0
$QEMU_IO -c 'w 3M 1M' -f $IMGFMT "$TEST_IMG.base" | _filter_qemu_io
# Create initial image and populate two bitmaps: one active, one inactive.
ORIG_IMG=$TEST_IMG
TEST_IMG=$TEST_IMG.orig
_make_test_img -b "$ORIG_IMG.base" -F $IMGFMT 10M
$QEMU_IO -c 'w 0 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
$QEMU_IMG bitmap --add -g 512k -f $IMGFMT "$TEST_IMG" b1
$QEMU_IMG bitmap --add --disable -f $IMGFMT "$TEST_IMG" b2
$QEMU_IO -c 'w 3M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
$QEMU_IMG bitmap --clear -f $IMGFMT "$TEST_IMG" b1
$QEMU_IO -c 'w 1M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
$QEMU_IMG bitmap --disable -f $IMGFMT "$TEST_IMG" b1
$QEMU_IMG bitmap --enable -f $IMGFMT "$TEST_IMG" b2
$QEMU_IO -c 'w 2M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
echo
echo "=== Bitmap preservation not possible to non-qcow2 ==="
echo
TEST_IMG=$ORIG_IMG
$QEMU_IMG convert --bitmaps -O raw "$TEST_IMG.orig" "$TEST_IMG" &&
echo "unexpected success"
echo
echo "=== Convert with bitmap preservation ==="
echo
# Only bitmaps from the active layer are copied
$QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG.orig" "$TEST_IMG"
_img_info --format-specific | _filter_irrelevant_img_info
# But we can also merge in bitmaps from other layers. This test is a bit
# contrived to cover more code paths, in reality, you could merge directly
# into b0 without going through tmp
$QEMU_IMG bitmap --add --disable -f $IMGFMT "$TEST_IMG" b0
$QEMU_IMG bitmap --add --merge b0 -b "$TEST_IMG.base" -F $IMGFMT \
-f $IMGFMT "$TEST_IMG" tmp
$QEMU_IMG bitmap --merge tmp -f $IMGFMT "$TEST_IMG" b0
$QEMU_IMG bitmap --remove --image-opts \
driver=$IMGFMT,file.driver=file,file.filename="$TEST_IMG" tmp
_img_info --format-specific | _filter_irrelevant_img_info
echo
echo "=== Merge from top layer into backing image ==="
echo
$QEMU_IMG rebase -u -F qcow2 -b "$TEST_IMG.base" "$TEST_IMG"
$QEMU_IMG bitmap --add --merge b2 -b "$TEST_IMG" -F $IMGFMT \
-f $IMGFMT "$TEST_IMG.base" b3
_img_info --format-specific --backing-chain | _filter_irrelevant_img_info
echo
echo "=== Check bitmap contents ==="
echo
# x-dirty-bitmap is a hack for reading bitmaps; it abuses block status to
# report "data":false for portions of the bitmap which are set
IMG="driver=nbd,server.type=unix,server.path=$nbd_unix_socket"
nbd_server_start_unix_socket -r -f qcow2 \
-B b0 -B b1 -B b2 -B b3 "$TEST_IMG"
$QEMU_IMG map --output=json --image-opts \
"$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b0" | _filter_qemu_img_map
$QEMU_IMG map --output=json --image-opts \
"$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b1" | _filter_qemu_img_map
$QEMU_IMG map --output=json --image-opts \
"$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map
$QEMU_IMG map --output=json --image-opts \
"$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b3" | _filter_qemu_img_map
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
status=0