X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=blockdev-nbd.c;h=8174023e5c4741d588d7be1153b751ccdc19d4fd;hb=64e3d4032296aae1adf80e6638b2c4b1987a70d0;hp=582ffded77fefe9b77d96a385b53e8c88c54e1fe;hpb=3fa4c76590569f9dc128beb3eee65aaefcb6321e;p=mirror_qemu.git diff --git a/blockdev-nbd.c b/blockdev-nbd.c index 582ffded77..8174023e5c 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -14,8 +14,7 @@ #include "sysemu/block-backend.h" #include "hw/block/block.h" #include "qapi/error.h" -#include "qapi/qapi-commands-block.h" -#include "sysemu/sysemu.h" +#include "qapi/qapi-commands-block-export.h" #include "block/nbd.h" #include "io/channel-socket.h" #include "io/net-listener.h" @@ -23,23 +22,53 @@ typedef struct NBDServerData { QIONetListener *listener; QCryptoTLSCreds *tlscreds; + char *tlsauthz; + uint32_t max_connections; + uint32_t connections; } NBDServerData; static NBDServerData *nbd_server; +static bool is_qemu_nbd; + +static void nbd_update_server_watch(NBDServerData *s); + +void nbd_server_is_qemu_nbd(bool value) +{ + is_qemu_nbd = value; +} + +bool nbd_server_is_running(void) +{ + return nbd_server || is_qemu_nbd; +} static void nbd_blockdev_client_closed(NBDClient *client, bool ignored) { nbd_client_put(client); + assert(nbd_server->connections > 0); + nbd_server->connections--; + nbd_update_server_watch(nbd_server); } static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc, gpointer opaque) { + nbd_server->connections++; + nbd_update_server_watch(nbd_server); + qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server"); - nbd_client_new(cioc, nbd_server->tlscreds, NULL, + nbd_client_new(cioc, nbd_server->tlscreds, nbd_server->tlsauthz, nbd_blockdev_client_closed); } +static void nbd_update_server_watch(NBDServerData *s) +{ + if (!s->max_connections || s->connections < s->max_connections) { + qio_net_listener_set_client_func(s->listener, nbd_accept, NULL, NULL); + } else { + qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL); + } +} static void nbd_server_free(NBDServerData *server) { @@ -52,6 +81,7 @@ static void nbd_server_free(NBDServerData *server) if (server->tlscreds) { object_unref(OBJECT(server->tlscreds)); } + g_free(server->tlsauthz); g_free(server); } @@ -87,6 +117,7 @@ static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp) void nbd_server_start(SocketAddress *addr, const char *tls_creds, + const char *tls_authz, uint32_t max_connections, Error **errp) { if (nbd_server) { @@ -95,12 +126,13 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds, } nbd_server = g_new0(NBDServerData, 1); + nbd_server->max_connections = max_connections; nbd_server->listener = qio_net_listener_new(); qio_net_listener_set_name(nbd_server->listener, "nbd-listener"); - if (qio_net_listener_open_sync(nbd_server->listener, addr, errp) < 0) { + if (qio_net_listener_open_sync(nbd_server->listener, addr, 1, errp) < 0) { goto error; } @@ -117,10 +149,9 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds, } } - qio_net_listener_set_client_func(nbd_server->listener, - nbd_accept, - NULL, - NULL); + nbd_server->tlsauthz = g_strdup(tls_authz); + + nbd_update_server_watch(nbd_server); return; @@ -129,86 +160,102 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds, nbd_server = NULL; } +void nbd_server_start_options(NbdServerOptions *arg, Error **errp) +{ + nbd_server_start(arg->addr, arg->tls_creds, arg->tls_authz, + arg->max_connections, errp); +} + void qmp_nbd_server_start(SocketAddressLegacy *addr, bool has_tls_creds, const char *tls_creds, + bool has_tls_authz, const char *tls_authz, + bool has_max_connections, uint32_t max_connections, Error **errp) { SocketAddress *addr_flat = socket_address_flatten(addr); - nbd_server_start(addr_flat, tls_creds, errp); + nbd_server_start(addr_flat, tls_creds, tls_authz, max_connections, errp); qapi_free_SocketAddress(addr_flat); } -void qmp_nbd_server_add(const char *device, bool has_name, const char *name, - bool has_writable, bool writable, Error **errp) +void qmp_nbd_server_add(NbdServerAddOptions *arg, Error **errp) { - BlockDriverState *bs = NULL; + BlockExport *export; + BlockDriverState *bs; BlockBackend *on_eject_blk; - NBDExport *exp; + BlockExportOptions *export_opts; - if (!nbd_server) { - error_setg(errp, "NBD server not running"); + bs = bdrv_lookup_bs(arg->device, arg->device, errp); + if (!bs) { return; } - if (!has_name) { - name = device; + /* + * block-export-add would default to the node-name, but we may have to use + * the device name as a default here for compatibility. + */ + if (!arg->has_name) { + arg->name = arg->device; } - if (nbd_export_find(name)) { - error_setg(errp, "NBD server already has export named '%s'", name); - return; - } - - on_eject_blk = blk_by_name(device); - - bs = bdrv_lookup_bs(device, device, errp); - if (!bs) { - return; + export_opts = g_new(BlockExportOptions, 1); + *export_opts = (BlockExportOptions) { + .type = BLOCK_EXPORT_TYPE_NBD, + .id = g_strdup(arg->name), + .node_name = g_strdup(bdrv_get_node_name(bs)), + .has_writable = arg->has_writable, + .writable = arg->writable, + .u.nbd = { + .has_name = true, + .name = g_strdup(arg->name), + .has_description = arg->has_description, + .description = g_strdup(arg->description), + .has_bitmap = arg->has_bitmap, + .bitmap = g_strdup(arg->bitmap), + }, + }; + + /* + * nbd-server-add doesn't complain when a read-only device should be + * exported as writable, but simply downgrades it. This is an error with + * block-export-add. + */ + if (bdrv_is_read_only(bs)) { + export_opts->has_writable = true; + export_opts->writable = false; } - if (!has_writable) { - writable = false; - } - if (bdrv_is_read_only(bs)) { - writable = false; + export = blk_exp_add(export_opts, errp); + if (!export) { + goto fail; } - exp = nbd_export_new(bs, 0, -1, name, NULL, - writable ? 0 : NBD_FLAG_READ_ONLY, - NULL, false, on_eject_blk, errp); - if (!exp) { - return; + /* + * nbd-server-add removes the export when the named BlockBackend used for + * @device goes away. + */ + on_eject_blk = blk_by_name(arg->device); + if (on_eject_blk) { + nbd_export_set_on_eject_blk(export, on_eject_blk); } - /* 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); +fail: + qapi_free_BlockExportOptions(export_opts); } void qmp_nbd_server_remove(const char *name, - bool has_mode, NbdServerRemoveMode mode, + bool has_mode, BlockExportRemoveMode mode, Error **errp) { - NBDExport *exp; - - if (!nbd_server) { - error_setg(errp, "NBD server not running"); - return; - } + BlockExport *exp; - exp = nbd_export_find(name); - if (exp == NULL) { - error_setg(errp, "Export '%s' is not found", name); + exp = blk_exp_find(name); + if (exp && exp->drv->type != BLOCK_EXPORT_TYPE_NBD) { + error_setg(errp, "Block export '%s' is not an NBD export", name); return; } - if (!has_mode) { - mode = NBD_SERVER_REMOVE_MODE_SAFE; - } - - nbd_export_remove(exp, mode, errp); + qmp_block_export_del(name, has_mode, mode, errp); } void qmp_nbd_server_stop(Error **errp) @@ -218,31 +265,8 @@ void qmp_nbd_server_stop(Error **errp) return; } - nbd_export_close_all(); + blk_exp_close_all_type(BLOCK_EXPORT_TYPE_NBD); nbd_server_free(nbd_server); nbd_server = NULL; } - -void qmp_x_nbd_server_add_bitmap(const char *name, const char *bitmap, - bool has_bitmap_export_name, - const char *bitmap_export_name, - Error **errp) -{ - NBDExport *exp; - - if (!nbd_server) { - error_setg(errp, "NBD server not running"); - return; - } - - exp = nbd_export_find(name); - if (exp == NULL) { - error_setg(errp, "Export '%s' is not found", name); - return; - } - - nbd_export_bitmap(exp, bitmap, - has_bitmap_export_name ? bitmap_export_name : bitmap, - errp); -}