mirror of
https://github.com/xemu-project/xemu.git
synced 2025-04-02 11:11:48 -04:00
Our initial implementation of x-nbd-server-add-bitmap put in a restriction because of incremental backups: in that usage, we are exporting one qcow2 file (the temporary overlay target of a blockdev-backup sync:none job) and a dirty bitmap owned by a second qcow2 file (the source of the blockdev-backup, which is the backing file of the temporary). While both qcow2 files are still writable (the target in order to capture copy-on-write of old contents, and the source in order to track live guest writes in the meantime), the NBD client expects to see constant data, including the dirty bitmap. An enabled bitmap in the source would be modified by guest writes, which is at odds with the NBD export being a read-only constant view, hence the initial code choice of enforcing a disabled bitmap (the intent is that the exposed bitmap was disabled in the same transaction that started the blockdev-backup job, although we don't want to track enough state to actually enforce that). However, consider the case of a bitmap contained in a read-only node (including when the bitmap is found in a backing layer of the active image). Because the node can't be modified, the bitmap won't change due to writes, regardless of whether it is still enabled. Forbidding the export unless the bitmap is disabled is awkward, paritcularly since we can't change the bitmap to be disabled (because the node is read-only). Alternatively, consider the case of live storage migration, where management directs the destination to create a writable NBD server, then performs a drive-mirror from the source to the target, prior to doing the rest of the live migration. Since storage migration can be time-consuming, it may be wise to let the destination include a dirty bitmap to track which portions it has already received, where even if the migration is interrupted and restarted, the source can query the destination block status in order to potentially minimize re-sending data that has not changed in the meantime on a second attempt. Such code has not been written, and might not be trivial (after all, a cluster being marked dirty in the bitmap does not necessarily guarantee it has the desired contents), but it makes sense that letting an active dirty bitmap be exposed and changing alongside writes may prove useful in the future. Solve both issues by gating the restriction against a disabled bitmap to only happen when the caller has requested a read-only export, and where the BDS that owns the bitmap (whether or not it is the BDS handed to nbd_export_new() or from its backing chain) is still writable. We could drop the check altogether (if management apps are prepared to deal with a changing bitmap even on a read-only image), but for now keeping a check for the read-only case still stands a chance of preventing management errors. Update iotest 223 to show the looser behavior by leaving a bitmap enabled the whole run; note that we have to tear down and re-export a node when handling an error. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <20190111194720.15671-4-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
185 lines
5.9 KiB
Bash
Executable file
185 lines
5.9 KiB
Bash
Executable file
#!/bin/bash
|
|
#
|
|
# Test reading dirty bitmap over NBD
|
|
#
|
|
# Copyright (C) 2018 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
|
|
_cleanup_qemu
|
|
rm -f "$TEST_DIR/nbd"
|
|
}
|
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
|
|
|
# get standard environment, filters and checks
|
|
. ./common.rc
|
|
. ./common.filter
|
|
. ./common.qemu
|
|
|
|
_supported_fmt qcow2
|
|
_supported_proto file # uses NBD as well
|
|
_supported_os Linux
|
|
# Persistent dirty bitmaps require compat=1.1
|
|
_unsupported_imgopts 'compat=0.10'
|
|
|
|
do_run_qemu()
|
|
{
|
|
echo Testing: "$@"
|
|
$QEMU -nographic -qmp stdio -serial none "$@"
|
|
echo
|
|
}
|
|
|
|
run_qemu()
|
|
{
|
|
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
|
|
| _filter_qemu | _filter_imgfmt \
|
|
| _filter_actual_image_size
|
|
}
|
|
|
|
echo
|
|
echo "=== Create partially sparse image, then add dirty bitmaps ==="
|
|
echo
|
|
|
|
# Two bitmaps, to contrast granularity issues
|
|
# Also note that b will be disabled, while b2 is left enabled, to
|
|
# check for read-only interactions
|
|
_make_test_img -o cluster_size=4k 4M
|
|
$QEMU_IO -c 'w -P 0x11 1M 2M' "$TEST_IMG" | _filter_qemu_io
|
|
run_qemu <<EOF
|
|
{ "execute": "qmp_capabilities" }
|
|
{ "execute": "blockdev-add",
|
|
"arguments": {
|
|
"driver": "$IMGFMT",
|
|
"node-name": "n",
|
|
"file": {
|
|
"driver": "file",
|
|
"filename": "$TEST_IMG"
|
|
}
|
|
}
|
|
}
|
|
{ "execute": "block-dirty-bitmap-add",
|
|
"arguments": {
|
|
"node": "n",
|
|
"name": "b",
|
|
"persistent": true,
|
|
"granularity": 65536
|
|
}
|
|
}
|
|
{ "execute": "block-dirty-bitmap-add",
|
|
"arguments": {
|
|
"node": "n",
|
|
"name": "b2",
|
|
"persistent": true,
|
|
"granularity": 512
|
|
}
|
|
}
|
|
{ "execute": "quit" }
|
|
EOF
|
|
|
|
echo
|
|
echo "=== Write part of the file under active bitmap ==="
|
|
echo
|
|
|
|
$QEMU_IO -c 'w -P 0x22 512 512' -c 'w -P 0x33 2M 2M' "$TEST_IMG" \
|
|
| _filter_qemu_io
|
|
|
|
echo
|
|
echo "=== End dirty bitmaps, and start serving image over NBD ==="
|
|
echo
|
|
|
|
_launch_qemu 2> >(_filter_nbd)
|
|
|
|
# Intentionally provoke some errors as well, to check error handling
|
|
silent=
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"qmp_capabilities"}' "return"
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"blockdev-add",
|
|
"arguments":{"driver":"qcow2", "node-name":"n",
|
|
"file":{"driver":"file", "filename":"'"$TEST_IMG"'"}}}' "return"
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"block-dirty-bitmap-disable",
|
|
"arguments":{"node":"n", "name":"b"}}' "return"
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
|
|
"arguments":{"device":"n"}}' "error" # Attempt add without server
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start",
|
|
"arguments":{"addr":{"type":"unix",
|
|
"data":{"path":"'"$TEST_DIR/nbd"'"}}}}' "return"
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start",
|
|
"arguments":{"addr":{"type":"unix",
|
|
"data":{"path":"'"$TEST_DIR/nbd"1'"}}}}' "error" # Attempt second server
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
|
|
"arguments":{"device":"n"}}' "return"
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
|
|
"arguments":{"device":"nosuch"}}' "error" # Attempt to export missing node
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
|
|
"arguments":{"device":"n"}}' "error" # Attempt to export same name twice
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap",
|
|
"arguments":{"name":"n", "bitmap":"b"}}' "return"
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
|
|
"arguments":{"device":"n", "name":"n2"}}' "return"
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap",
|
|
"arguments":{"name":"n2", "bitmap":"b2"}}' "error" # Enabled vs. read-only
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove",
|
|
"arguments":{"name":"n2"}}' "return"
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
|
|
"arguments":{"device":"n", "name":"n2", "writable":true}}' "return"
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap",
|
|
"arguments":{"name":"n2", "bitmap":"b2"}}' "return"
|
|
|
|
echo
|
|
echo "=== Contrast normal status to large granularity dirty-bitmap ==="
|
|
echo
|
|
|
|
QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT
|
|
IMG="driver=nbd,export=n,server.type=unix,server.path=$TEST_DIR/nbd"
|
|
$QEMU_IO -r -c 'r -P 0x22 512 512' -c 'r -P 0 512k 512k' -c 'r -P 0x11 1m 1m' \
|
|
-c 'r -P 0x33 2m 2m' --image-opts "$IMG" | _filter_qemu_io
|
|
$QEMU_IMG map --output=json --image-opts \
|
|
"$IMG" | _filter_qemu_img_map
|
|
$QEMU_IMG map --output=json --image-opts \
|
|
"$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b" | _filter_qemu_img_map
|
|
|
|
echo
|
|
echo "=== Contrast to small granularity dirty-bitmap ==="
|
|
echo
|
|
|
|
IMG="driver=nbd,export=n2,server.type=unix,server.path=$TEST_DIR/nbd"
|
|
$QEMU_IMG map --output=json --image-opts \
|
|
"$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map
|
|
|
|
echo
|
|
echo "=== End NBD server ==="
|
|
echo
|
|
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove",
|
|
"arguments":{"name":"n"}}' "return"
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove",
|
|
"arguments":{"name":"n2"}}' "return"
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove",
|
|
"arguments":{"name":"n2"}}' "error" # Attempt duplicate clean
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-stop"}' "return"
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-stop"}' "error" # Again
|
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"quit"}' "return"
|
|
|
|
# success, all done
|
|
echo '*** done'
|
|
rm -f $seq.full
|
|
status=0
|