mirror of
https://gitlab.com/qemu-project/qemu.git
synced 2026-10-28 11:54:41 +08:00
qemu-nbd: Support -s and -l at the same time
qemu-nbd already has the ability to wrap a read-write layer on top of the export of a read-only image (-s) and the ability to export an internal snapshot rather than the main image in a qcow2 file (-l SNAPID). But it gave a confusing error message when trying to mix the two, because the snapshot overlay created first no longer has access to the internal snapshots of the image being wrapped. WIth a bit of finesse, this useful scenario is now supported. https://gitlab.com/qemu-project/qemu/-/work_items/159 Signed-off-by: Eric Blake <eblake@redhat.com> Message-ID: <20260408021636.794794-2-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> [eblake: improve test with Vladimir's suggestions, add lock to satisfy TSAN] Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
1 parent
b8c0e25800
commit
67a2606004
4 files changed
+143
-6
No files matched your search
@@ -95,9 +95,10 @@ driver options if :option:`--image-opts` is specified.
|
||||
|
||||
.. option:: -l, --load-snapshot=SNAPSHOT_PARAM
|
||||
|
||||
Load an internal snapshot inside *filename* and export it
|
||||
as an read-only device, SNAPSHOT_PARAM format is
|
||||
``snapshot.id=[ID],snapshot.name=[NAME]`` or ``[ID_OR_NAME]``
|
||||
Load an internal snapshot inside *filename* and export it.
|
||||
SNAPSHOT_PARAM format is ``snapshot.id=[ID],snapshot.name=[NAME]``
|
||||
or ``[ID_OR_NAME]``. The export is read-only unless ``-s`` is also
|
||||
in use.
|
||||
|
||||
.. option:: --cache=CACHE
|
||||
|
||||
|
||||
+19
-3
@@ -534,6 +534,7 @@ int main(int argc, char **argv)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs;
|
||||
BlockDriverState *orig_bs;
|
||||
uint64_t dev_offset = 0;
|
||||
bool readonly = false;
|
||||
bool disconnect = false;
|
||||
@@ -716,7 +717,7 @@ int main(int argc, char **argv)
|
||||
} else {
|
||||
sn_id_or_name = optarg;
|
||||
}
|
||||
/* fall through */
|
||||
break;
|
||||
case 'r':
|
||||
readonly = true;
|
||||
flags &= ~BDRV_O_RDWR;
|
||||
@@ -1110,6 +1111,15 @@ int main(int argc, char **argv)
|
||||
bdrv_init();
|
||||
atexit(qemu_nbd_shutdown);
|
||||
|
||||
/*
|
||||
* -s and -l can be used together to create read-write wrapper
|
||||
* around an internal snapshot. Otherwise, -l in isolation implies
|
||||
* read-only.
|
||||
*/
|
||||
if ((sn_opts || sn_id_or_name) && (flags & BDRV_O_SNAPSHOT) == 0) {
|
||||
readonly = true;
|
||||
flags &= ~BDRV_O_RDWR;
|
||||
}
|
||||
opts.srcpath = argv[optind];
|
||||
if (imageOpts) {
|
||||
QemuOpts *o;
|
||||
@@ -1155,13 +1165,19 @@ int main(int argc, char **argv)
|
||||
|
||||
blk_set_enable_write_cache(blk, !writethrough);
|
||||
|
||||
orig_bs = bs;
|
||||
if (flags & BDRV_O_SNAPSHOT) {
|
||||
WITH_GRAPH_RDLOCK_GUARD() {
|
||||
orig_bs = bs->backing->bs;
|
||||
}
|
||||
}
|
||||
if (sn_opts) {
|
||||
ret = bdrv_snapshot_load_tmp(bs,
|
||||
ret = bdrv_snapshot_load_tmp(orig_bs,
|
||||
qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID),
|
||||
qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME),
|
||||
&local_err);
|
||||
} else if (sn_id_or_name) {
|
||||
ret = bdrv_snapshot_load_tmp_by_id_or_name(bs, sn_id_or_name,
|
||||
ret = bdrv_snapshot_load_tmp_by_id_or_name(orig_bs, sn_id_or_name,
|
||||
&local_err);
|
||||
}
|
||||
if (ret < 0) {
|
||||
|
||||
Executable
+81
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env bash
|
||||
# group: rw quick
|
||||
#
|
||||
# Test qemu-nbd snapshot handling
|
||||
#
|
||||
# Copyright (C) Red Hat, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
seq="$(basename $0)"
|
||||
echo "QA output created by $seq"
|
||||
|
||||
status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
_cleanup_test_img
|
||||
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
|
||||
_supported_os Linux
|
||||
_require_command QEMU_NBD
|
||||
|
||||
echo
|
||||
echo "=== Initial image setup ==="
|
||||
echo
|
||||
|
||||
# Create qcow2 image with one internal snapshot
|
||||
_make_test_img 10M
|
||||
$QEMU_IO -c 'w -P 1 3M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
|
||||
$QEMU_IMG snapshot -c snap -f $IMGFMT "$TEST_IMG" | _filter_qemu_img
|
||||
$QEMU_IO -c 'w -P 2 3M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
echo
|
||||
echo "=== Main image in snapshot mode ==="
|
||||
echo
|
||||
|
||||
nbd_server_start_unix_socket -s -f qcow2 "$TEST_IMG"
|
||||
$QEMU_IO -c 'r -P 2 3M 1M' -c 'w -P 3 3M 1M' -c 'r -P 3 3M 1M' -f raw \
|
||||
nbd:unix:$nbd_unix_socket | _filter_qemu_io
|
||||
nbd_server_stop
|
||||
|
||||
echo
|
||||
echo "=== Read-only snapshot access ==="
|
||||
echo
|
||||
|
||||
nbd_server_start_unix_socket -l snap -f qcow2 "$TEST_IMG"
|
||||
$QEMU_IO -r -c 'r -P 1 3M 1M' -f raw \
|
||||
nbd:unix:$nbd_unix_socket | _filter_qemu_io
|
||||
$QEMU_IO -c 'r -P 1 3M 1M' -f raw \
|
||||
nbd:unix:$nbd_unix_socket 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
nbd_server_stop
|
||||
|
||||
echo
|
||||
echo "=== Combine -s and -l for read-write internal snapshot access ==="
|
||||
echo
|
||||
|
||||
nbd_server_start_unix_socket -s -l snap -f qcow2 "$TEST_IMG"
|
||||
$QEMU_IO -c 'r -P 1 3M 1M' -c 'w -P 3 3M 1M' -c 'r -P 3 3M 1M' -f raw \
|
||||
nbd:unix:$nbd_unix_socket | _filter_qemu_io
|
||||
nbd_server_stop
|
||||
|
||||
echo
|
||||
echo "=== Check that original image is unchanged ==="
|
||||
echo
|
||||
|
||||
$QEMU_IO -c 'r -P 2 3M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
# success, all done
|
||||
echo '*** done'
|
||||
rm -f $seq.full
|
||||
status=0
|
||||
@@ -0,0 +1,39 @@
|
||||
QA output created by qemu-nbd-snapshots
|
||||
|
||||
=== Initial image setup ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760
|
||||
wrote 1048576/1048576 bytes at offset 3145728
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 1048576/1048576 bytes at offset 3145728
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
=== Main image in snapshot mode ===
|
||||
|
||||
read 1048576/1048576 bytes at offset 3145728
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 1048576/1048576 bytes at offset 3145728
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 1048576/1048576 bytes at offset 3145728
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
=== Read-only snapshot access ===
|
||||
|
||||
read 1048576/1048576 bytes at offset 3145728
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
qemu-io: can't open device nbd:unix:SOCK_DIR/qemu-nbd.sock: Could not open image: Permission denied
|
||||
|
||||
=== Combine -s and -l for read-write internal snapshot access ===
|
||||
|
||||
read 1048576/1048576 bytes at offset 3145728
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 1048576/1048576 bytes at offset 3145728
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 1048576/1048576 bytes at offset 3145728
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
=== Check that original image is unchanged ===
|
||||
|
||||
read 1048576/1048576 bytes at offset 3145728
|
||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
*** done
|
||||
Reference in new issue
Block a user