diff --git a/blockdev-nbd.c b/blockdev-nbd.c index 213f226ac1..6a8b206e1d 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -151,6 +151,7 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, BlockBackend *on_eject_blk; NBDExport *exp; int64_t len; + AioContext *aio_context; if (!nbd_server) { error_setg(errp, "NBD server not running"); @@ -173,11 +174,13 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, return; } + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); len = bdrv_getlength(bs); if (len < 0) { error_setg_errno(errp, -len, "Failed to determine the NBD export's length"); - return; + goto out; } if (!has_writable) { @@ -190,13 +193,16 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, exp = nbd_export_new(bs, 0, len, name, NULL, bitmap, !writable, !writable, NULL, false, on_eject_blk, errp); if (!exp) { - return; + goto out; } /* The list of named exports has a strong reference to this export now and * our only way of accessing it is through nbd_export_find(), so we can drop * the strong reference that is @exp. */ nbd_export_put(exp); + + out: + aio_context_release(aio_context); } void qmp_nbd_server_remove(const char *name, @@ -204,6 +210,7 @@ void qmp_nbd_server_remove(const char *name, Error **errp) { NBDExport *exp; + AioContext *aio_context; if (!nbd_server) { error_setg(errp, "NBD server not running"); @@ -220,7 +227,10 @@ void qmp_nbd_server_remove(const char *name, mode = NBD_SERVER_REMOVE_MODE_SAFE; } + aio_context = nbd_export_aio_context(exp); + aio_context_acquire(aio_context); nbd_export_remove(exp, mode, errp); + aio_context_release(aio_context); } void qmp_nbd_server_stop(Error **errp) diff --git a/include/block/nbd.h b/include/block/nbd.h index 21550747cf..316fd705a9 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -340,6 +340,7 @@ void nbd_export_put(NBDExport *exp); BlockBackend *nbd_export_get_blockdev(NBDExport *exp); +AioContext *nbd_export_aio_context(NBDExport *exp); NBDExport *nbd_export_find(const char *name); void nbd_export_close_all(void); diff --git a/nbd/client.c b/nbd/client.c index b9dc829175..f6733962b4 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -204,6 +204,7 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply, case NBD_REP_ERR_TLS_REQD: error_setg(errp, "TLS negotiation required before option %" PRIu32 " (%s)", reply->option, nbd_opt_lookup(reply->option)); + error_append_hint(errp, "Did you forget a valid tls-creds?\n"); break; case NBD_REP_ERR_UNKNOWN: diff --git a/nbd/server.c b/nbd/server.c index 28c3c8be85..d8d1e62455 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1297,6 +1297,11 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp) return ret; } + /* Attach the channel to the same AioContext as the export */ + if (client->exp && client->exp->ctx) { + qio_channel_attach_aio_context(client->ioc, client->exp->ctx); + } + assert(!client->optlen); trace_nbd_negotiate_success(); @@ -1456,7 +1461,12 @@ static void blk_aio_detach(void *opaque) static void nbd_eject_notifier(Notifier *n, void *data) { NBDExport *exp = container_of(n, NBDExport, eject_notifier); + AioContext *aio_context; + + aio_context = exp->ctx; + aio_context_acquire(aio_context); nbd_export_close(exp); + aio_context_release(aio_context); } NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, @@ -1475,12 +1485,11 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, * NBD exports are used for non-shared storage migration. Make sure * that BDRV_O_INACTIVE is cleared and the image is ready for write * access since the export could be available before migration handover. + * ctx was acquired in the caller. */ assert(name); ctx = bdrv_get_aio_context(bs); - aio_context_acquire(ctx); bdrv_invalidate_cache(bs, NULL); - aio_context_release(ctx); /* Don't allow resize while the NBD server is running, otherwise we don't * care what happens with the node. */ @@ -1488,7 +1497,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, if (!readonly) { perm |= BLK_PERM_WRITE; } - blk = blk_new(bdrv_get_aio_context(bs), perm, + blk = blk_new(ctx, perm, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD); ret = blk_insert_bs(blk, bs, errp); @@ -1555,7 +1564,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, } exp->close = close; - exp->ctx = blk_get_aio_context(blk); + exp->ctx = ctx; blk_add_aio_context_notifier(blk, blk_aio_attached, blk_aio_detach, exp); if (on_eject_blk) { @@ -1588,6 +1597,12 @@ NBDExport *nbd_export_find(const char *name) return NULL; } +AioContext * +nbd_export_aio_context(NBDExport *exp) +{ + return exp->ctx; +} + void nbd_export_close(NBDExport *exp) { NBDClient *client, *next; @@ -1682,9 +1697,13 @@ BlockBackend *nbd_export_get_blockdev(NBDExport *exp) void nbd_export_close_all(void) { NBDExport *exp, *next; + AioContext *aio_context; QTAILQ_FOREACH_SAFE(exp, &exports, next, next) { + aio_context = exp->ctx; + aio_context_acquire(aio_context); nbd_export_close(exp); + aio_context_release(aio_context); } } diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 index cc48e78ea7..2ba3d8124b 100755 --- a/tests/qemu-iotests/223 +++ b/tests/qemu-iotests/223 @@ -2,7 +2,7 @@ # # Test reading dirty bitmap over NBD # -# Copyright (C) 2018 Red Hat, Inc. +# Copyright (C) 2018-2019 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 @@ -109,7 +109,7 @@ echo echo "=== End dirty bitmaps, and start serving image over NBD ===" echo -_launch_qemu 2> >(_filter_nbd) +_launch_qemu -object iothread,id=io0 2> >(_filter_nbd) # Intentionally provoke some errors as well, to check error handling silent= @@ -117,6 +117,8 @@ _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":"x-blockdev-set-iothread", + "arguments":{"node-name":"n", "iothread":"io0"}}' "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", diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out index 5d00398c11..23b34fcd20 100644 --- a/tests/qemu-iotests/223.out +++ b/tests/qemu-iotests/223.out @@ -27,6 +27,7 @@ wrote 2097152/2097152 bytes at offset 2097152 {"return": {}} {"return": {}} {"return": {}} +{"return": {}} {"error": {"class": "GenericError", "desc": "NBD server not running"}} {"return": {}} {"error": {"class": "GenericError", "desc": "NBD server already running"}} diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out index 24321efa11..c3c344811b 100644 --- a/tests/qemu-iotests/233.out +++ b/tests/qemu-iotests/233.out @@ -21,8 +21,10 @@ server reported: TLS not configured == check plain client to TLS server fails == qemu-img: Could not open 'nbd://localhost:PORT': TLS negotiation required before option 7 (go) +Did you forget a valid tls-creds? server reported: Option 0x7 not permitted before TLS qemu-nbd: TLS negotiation required before option 3 (list) +Did you forget a valid tls-creds? server reported: Option 0x3 not permitted before TLS == check TLS works == diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 98ff3a1cce..bcc06d0e01 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -461,12 +461,13 @@ int inet_connect_saddr(InetSocketAddress *saddr, Error **errp) } } + freeaddrinfo(res); + if (sock < 0) { error_propagate(errp, local_err); + return sock; } - freeaddrinfo(res); - if (saddr->keep_alive) { int val = 1; int ret = qemu_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,