mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-07-21 10:24:33 +00:00
qemu-nbd: Add --bitmap=NAME option
Having to fire up qemu, then use QMP commands for nbd-server-start and nbd-server-add, just to expose a persistent dirty bitmap, is rather tedious. Make it possible to expose a dirty bitmap using just qemu-nbd (of course, for now this only works when qemu-nbd is visiting a BDS formatted as qcow2). Of course, any good feature also needs unit testing, so expand iotest 223 to cover it. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <20190111194720.15671-9-eblake@redhat.com>
This commit is contained in:
parent
678ba275c7
commit
636192c4b6
10
qemu-nbd.c
10
qemu-nbd.c
|
@ -95,6 +95,7 @@ static void usage(const char *name)
|
||||||
"Exposing part of the image:\n"
|
"Exposing part of the image:\n"
|
||||||
" -o, --offset=OFFSET offset into the image\n"
|
" -o, --offset=OFFSET offset into the image\n"
|
||||||
" -P, --partition=NUM only expose partition NUM\n"
|
" -P, --partition=NUM only expose partition NUM\n"
|
||||||
|
" -B, --bitmap=NAME expose a persistent dirty bitmap\n"
|
||||||
"\n"
|
"\n"
|
||||||
"General purpose options:\n"
|
"General purpose options:\n"
|
||||||
" --object type,id=ID,... define an object such as 'secret' for providing\n"
|
" --object type,id=ID,... define an object such as 'secret' for providing\n"
|
||||||
|
@ -509,7 +510,7 @@ int main(int argc, char **argv)
|
||||||
off_t fd_size;
|
off_t fd_size;
|
||||||
QemuOpts *sn_opts = NULL;
|
QemuOpts *sn_opts = NULL;
|
||||||
const char *sn_id_or_name = NULL;
|
const char *sn_id_or_name = NULL;
|
||||||
const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:D:";
|
const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:D:B:";
|
||||||
struct option lopt[] = {
|
struct option lopt[] = {
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "version", no_argument, NULL, 'V' },
|
{ "version", no_argument, NULL, 'V' },
|
||||||
|
@ -519,6 +520,7 @@ int main(int argc, char **argv)
|
||||||
{ "offset", required_argument, NULL, 'o' },
|
{ "offset", required_argument, NULL, 'o' },
|
||||||
{ "read-only", no_argument, NULL, 'r' },
|
{ "read-only", no_argument, NULL, 'r' },
|
||||||
{ "partition", required_argument, NULL, 'P' },
|
{ "partition", required_argument, NULL, 'P' },
|
||||||
|
{ "bitmap", required_argument, NULL, 'B' },
|
||||||
{ "connect", required_argument, NULL, 'c' },
|
{ "connect", required_argument, NULL, 'c' },
|
||||||
{ "disconnect", no_argument, NULL, 'd' },
|
{ "disconnect", no_argument, NULL, 'd' },
|
||||||
{ "snapshot", no_argument, NULL, 's' },
|
{ "snapshot", no_argument, NULL, 's' },
|
||||||
|
@ -558,6 +560,7 @@ int main(int argc, char **argv)
|
||||||
QDict *options = NULL;
|
QDict *options = NULL;
|
||||||
const char *export_name = ""; /* Default export name */
|
const char *export_name = ""; /* Default export name */
|
||||||
const char *export_description = NULL;
|
const char *export_description = NULL;
|
||||||
|
const char *bitmap = NULL;
|
||||||
const char *tlscredsid = NULL;
|
const char *tlscredsid = NULL;
|
||||||
bool imageOpts = false;
|
bool imageOpts = false;
|
||||||
bool writethrough = true;
|
bool writethrough = true;
|
||||||
|
@ -695,6 +698,9 @@ int main(int argc, char **argv)
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'B':
|
||||||
|
bitmap = optarg;
|
||||||
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
sockpath = optarg;
|
sockpath = optarg;
|
||||||
if (sockpath[0] != '/') {
|
if (sockpath[0] != '/') {
|
||||||
|
@ -1016,7 +1022,7 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
export = nbd_export_new(bs, dev_offset, fd_size, export_name,
|
export = nbd_export_new(bs, dev_offset, fd_size, export_name,
|
||||||
export_description, NULL, nbdflags,
|
export_description, bitmap, nbdflags,
|
||||||
nbd_export_closed, writethrough, NULL,
|
nbd_export_closed, writethrough, NULL,
|
||||||
&error_fatal);
|
&error_fatal);
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,10 @@ auto-detecting
|
||||||
Export the disk as read-only
|
Export the disk as read-only
|
||||||
@item -P, --partition=@var{num}
|
@item -P, --partition=@var{num}
|
||||||
Only expose partition @var{num}
|
Only expose partition @var{num}
|
||||||
|
@item -B, --bitmap=@var{name}
|
||||||
|
If @var{filename} has a qcow2 persistent bitmap @var{name}, expose
|
||||||
|
that bitmap via the ``qemu:dirty-bitmap:@var{name}'' context
|
||||||
|
accessible through NBD_OPT_SET_META_CONTEXT.
|
||||||
@item -s, --snapshot
|
@item -s, --snapshot
|
||||||
Use @var{filename} as an external snapshot, create a temporary
|
Use @var{filename} as an external snapshot, create a temporary
|
||||||
file with backing_file=@var{filename}, redirect the write to
|
file with backing_file=@var{filename}, redirect the write to
|
||||||
|
|
|
@ -25,6 +25,7 @@ status=1 # failure is the default!
|
||||||
|
|
||||||
_cleanup()
|
_cleanup()
|
||||||
{
|
{
|
||||||
|
nbd_server_stop
|
||||||
_cleanup_test_img
|
_cleanup_test_img
|
||||||
_cleanup_qemu
|
_cleanup_qemu
|
||||||
rm -f "$TEST_DIR/nbd"
|
rm -f "$TEST_DIR/nbd"
|
||||||
|
@ -35,6 +36,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
. ./common.rc
|
. ./common.rc
|
||||||
. ./common.filter
|
. ./common.filter
|
||||||
. ./common.qemu
|
. ./common.qemu
|
||||||
|
. ./common.nbd
|
||||||
|
|
||||||
_supported_fmt qcow2
|
_supported_fmt qcow2
|
||||||
_supported_proto file # uses NBD as well
|
_supported_proto file # uses NBD as well
|
||||||
|
@ -163,7 +165,7 @@ $QEMU_IMG map --output=json --image-opts \
|
||||||
"$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map
|
"$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "=== End NBD server ==="
|
echo "=== End qemu NBD server ==="
|
||||||
echo
|
echo
|
||||||
|
|
||||||
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove",
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove",
|
||||||
|
@ -176,6 +178,20 @@ _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":"nbd-server-stop"}' "error" # Again
|
||||||
_send_qemu_cmd $QEMU_HANDLE '{"execute":"quit"}' "return"
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"quit"}' "return"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== Use qemu-nbd as server ==="
|
||||||
|
echo
|
||||||
|
|
||||||
|
nbd_server_start_unix_socket -r -f $IMGFMT -B b "$TEST_IMG"
|
||||||
|
IMG="driver=nbd,server.type=unix,server.path=$nbd_unix_socket"
|
||||||
|
$QEMU_IMG map --output=json --image-opts \
|
||||||
|
"$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b" | _filter_qemu_img_map
|
||||||
|
|
||||||
|
nbd_server_start_unix_socket -f $IMGFMT -B b2 "$TEST_IMG"
|
||||||
|
IMG="driver=nbd,server.type=unix,server.path=$nbd_unix_socket"
|
||||||
|
$QEMU_IMG map --output=json --image-opts \
|
||||||
|
"$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map
|
||||||
|
|
||||||
# success, all done
|
# success, all done
|
||||||
echo '*** done'
|
echo '*** done'
|
||||||
rm -f $seq.full
|
rm -f $seq.full
|
||||||
|
|
|
@ -61,7 +61,7 @@ read 2097152/2097152 bytes at offset 2097152
|
||||||
{ "start": 1024, "length": 2096128, "depth": 0, "zero": false, "data": true},
|
{ "start": 1024, "length": 2096128, "depth": 0, "zero": false, "data": true},
|
||||||
{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}]
|
{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}]
|
||||||
|
|
||||||
=== End NBD server ===
|
=== End qemu NBD server ===
|
||||||
|
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
|
@ -69,4 +69,14 @@ read 2097152/2097152 bytes at offset 2097152
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"error": {"class": "GenericError", "desc": "NBD server not running"}}
|
{"error": {"class": "GenericError", "desc": "NBD server not running"}}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
|
|
||||||
|
=== Use qemu-nbd as server ===
|
||||||
|
|
||||||
|
[{ "start": 0, "length": 65536, "depth": 0, "zero": false, "data": false},
|
||||||
|
{ "start": 65536, "length": 2031616, "depth": 0, "zero": false, "data": true},
|
||||||
|
{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}]
|
||||||
|
[{ "start": 0, "length": 512, "depth": 0, "zero": false, "data": true},
|
||||||
|
{ "start": 512, "length": 512, "depth": 0, "zero": false, "data": false},
|
||||||
|
{ "start": 1024, "length": 2096128, "depth": 0, "zero": false, "data": true},
|
||||||
|
{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}]
|
||||||
*** done
|
*** done
|
||||||
|
|
Loading…
Reference in a new issue