#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "hw/block/block.h"
-#include "qapi/qmp/qerror.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-block.h"
#include "sysemu/sysemu.h"
-#include "qmp-commands.h"
#include "block/nbd.h"
#include "io/channel-socket.h"
+#include "io/net-listener.h"
typedef struct NBDServerData {
- QIOChannelSocket *listen_ioc;
- int watch;
+ QIONetListener *listener;
QCryptoTLSCreds *tlscreds;
+ char *tlsauthz;
} NBDServerData;
static NBDServerData *nbd_server;
-
-static gboolean nbd_accept(QIOChannel *ioc, GIOCondition condition,
- gpointer opaque)
+static void nbd_blockdev_client_closed(NBDClient *client, bool ignored)
{
- QIOChannelSocket *cioc;
-
- if (!nbd_server) {
- return FALSE;
- }
-
- cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
- NULL);
- if (!cioc) {
- return TRUE;
- }
+ nbd_client_put(client);
+}
+static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc,
+ gpointer opaque)
+{
qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server");
- nbd_client_new(NULL, cioc,
- nbd_server->tlscreds, NULL,
- nbd_client_put);
- object_unref(OBJECT(cioc));
- return TRUE;
+ nbd_client_new(cioc, nbd_server->tlscreds, nbd_server->tlsauthz,
+ nbd_blockdev_client_closed);
}
return;
}
- if (server->watch != -1) {
- g_source_remove(server->watch);
- }
- object_unref(OBJECT(server->listen_ioc));
+ qio_net_listener_disconnect(server->listener);
+ object_unref(OBJECT(server->listener));
if (server->tlscreds) {
object_unref(OBJECT(server->tlscreds));
}
+ g_free(server->tlsauthz);
g_free(server);
}
}
-void qmp_nbd_server_start(SocketAddress *addr,
- bool has_tls_creds, const char *tls_creds,
- Error **errp)
+void nbd_server_start(SocketAddress *addr, const char *tls_creds,
+ const char *tls_authz, Error **errp)
{
if (nbd_server) {
error_setg(errp, "NBD server already running");
}
nbd_server = g_new0(NBDServerData, 1);
- nbd_server->watch = -1;
- nbd_server->listen_ioc = qio_channel_socket_new();
- qio_channel_set_name(QIO_CHANNEL(nbd_server->listen_ioc),
- "nbd-listener");
- if (qio_channel_socket_listen_sync(
- nbd_server->listen_ioc, addr, errp) < 0) {
+ 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) {
goto error;
}
- if (has_tls_creds) {
+ if (tls_creds) {
nbd_server->tlscreds = nbd_get_tls_creds(tls_creds, errp);
if (!nbd_server->tlscreds) {
goto error;
}
- /* TODO SOCKET_ADDRESS_KIND_FD where fd has AF_INET or AF_INET6 */
- if (addr->type != SOCKET_ADDRESS_KIND_INET) {
+ /* TODO SOCKET_ADDRESS_TYPE_FD where fd has AF_INET or AF_INET6 */
+ if (addr->type != SOCKET_ADDRESS_TYPE_INET) {
error_setg(errp, "TLS is only supported with IPv4/IPv6");
goto error;
}
}
- nbd_server->watch = qio_channel_add_watch(
- QIO_CHANNEL(nbd_server->listen_ioc),
- G_IO_IN,
- nbd_accept,
- NULL,
- NULL);
+ nbd_server->tlsauthz = g_strdup(tls_authz);
+
+ qio_net_listener_set_client_func(nbd_server->listener,
+ nbd_accept,
+ NULL,
+ NULL);
return;
nbd_server = NULL;
}
-void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
- Error **errp)
+void qmp_nbd_server_start(SocketAddressLegacy *addr,
+ bool has_tls_creds, const char *tls_creds,
+ bool has_tls_authz, const char *tls_authz,
+ Error **errp)
+{
+ SocketAddress *addr_flat = socket_address_flatten(addr);
+
+ nbd_server_start(addr_flat, tls_creds, tls_authz, 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,
+ bool has_bitmap, const char *bitmap, Error **errp)
{
BlockDriverState *bs = NULL;
BlockBackend *on_eject_blk;
NBDExport *exp;
+ int64_t len;
if (!nbd_server) {
error_setg(errp, "NBD server not running");
return;
}
- if (nbd_export_find(device)) {
- error_setg(errp, "NBD server already exporting device '%s'", device);
+ if (!has_name) {
+ name = device;
+ }
+
+ if (nbd_export_find(name)) {
+ error_setg(errp, "NBD server already has export named '%s'", name);
return;
}
return;
}
+ len = bdrv_getlength(bs);
+ if (len < 0) {
+ error_setg_errno(errp, -len,
+ "Failed to determine the NBD export's length");
+ return;
+ }
+
if (!has_writable) {
writable = false;
}
writable = false;
}
- exp = nbd_export_new(bs, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY,
+ exp = nbd_export_new(bs, 0, len, name, NULL, bitmap,
+ writable ? 0 : NBD_FLAG_READ_ONLY,
NULL, false, on_eject_blk, errp);
if (!exp) {
return;
}
- nbd_export_set_name(exp, device);
-
/* 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);
}
+void qmp_nbd_server_remove(const char *name,
+ bool has_mode, NbdServerRemoveMode mode,
+ 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;
+ }
+
+ if (!has_mode) {
+ mode = NBD_SERVER_REMOVE_MODE_SAFE;
+ }
+
+ nbd_export_remove(exp, mode, errp);
+}
+
void qmp_nbd_server_stop(Error **errp)
{
+ if (!nbd_server) {
+ error_setg(errp, "NBD server not running");
+ return;
+ }
+
nbd_export_close_all();
nbd_server_free(nbd_server);