2012-08-22 22:43:07 +08:00
|
|
|
/*
|
|
|
|
* Serving QEMU block devices via NBD
|
|
|
|
*
|
|
|
|
* Copyright (c) 2012 Red Hat, Inc.
|
|
|
|
*
|
|
|
|
* Author: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or
|
|
|
|
* later. See the COPYING file in the top-level directory.
|
|
|
|
*/
|
|
|
|
|
2016-01-30 01:50:05 +08:00
|
|
|
#include "qemu/osdep.h"
|
2012-12-18 01:20:04 +08:00
|
|
|
#include "sysemu/blockdev.h"
|
2014-11-18 19:21:17 +08:00
|
|
|
#include "sysemu/block-backend.h"
|
2013-02-06 00:06:20 +08:00
|
|
|
#include "hw/block/block.h"
|
2018-02-01 19:18:31 +08:00
|
|
|
#include "qapi/error.h"
|
2020-10-27 13:05:48 +08:00
|
|
|
#include "qapi/clone-visitor.h"
|
|
|
|
#include "qapi/qapi-visit-block-export.h"
|
2020-09-24 23:26:48 +08:00
|
|
|
#include "qapi/qapi-commands-block-export.h"
|
2012-12-18 01:19:44 +08:00
|
|
|
#include "block/nbd.h"
|
2016-02-11 02:41:03 +08:00
|
|
|
#include "io/channel-socket.h"
|
2017-12-18 18:16:42 +08:00
|
|
|
#include "io/net-listener.h"
|
2012-08-22 22:43:07 +08:00
|
|
|
|
2016-02-11 02:41:14 +08:00
|
|
|
typedef struct NBDServerData {
|
2017-12-18 18:16:42 +08:00
|
|
|
QIONetListener *listener;
|
2016-02-11 02:41:14 +08:00
|
|
|
QCryptoTLSCreds *tlscreds;
|
nbd: allow authorization with nbd-server-start QMP command
As with the previous patch to qemu-nbd, the nbd-server-start QMP command
also needs to be able to specify authorization when enabling TLS encryption.
First the client must create a QAuthZ object instance using the
'object-add' command:
{
'execute': 'object-add',
'arguments': {
'qom-type': 'authz-list',
'id': 'authz0',
'parameters': {
'policy': 'deny',
'rules': [
{
'match': '*CN=fred',
'policy': 'allow'
}
]
}
}
}
They can then reference this in the new 'tls-authz' parameter when
executing the 'nbd-server-start' command:
{
'execute': 'nbd-server-start',
'arguments': {
'addr': {
'type': 'inet',
'host': '127.0.0.1',
'port': '9000'
},
'tls-creds': 'tls0',
'tls-authz': 'authz0'
}
}
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <20190227162035.18543-3-berrange@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
2019-02-28 00:20:34 +08:00
|
|
|
char *tlsauthz;
|
2020-09-24 23:26:54 +08:00
|
|
|
uint32_t max_connections;
|
|
|
|
uint32_t connections;
|
2016-02-11 02:41:14 +08:00
|
|
|
} NBDServerData;
|
|
|
|
|
|
|
|
static NBDServerData *nbd_server;
|
2022-05-12 08:49:23 +08:00
|
|
|
static int qemu_nbd_connections = -1; /* Non-negative if this is qemu-nbd */
|
2016-02-11 02:41:14 +08:00
|
|
|
|
2020-09-24 23:26:54 +08:00
|
|
|
static void nbd_update_server_watch(NBDServerData *s);
|
|
|
|
|
2022-05-12 08:49:23 +08:00
|
|
|
void nbd_server_is_qemu_nbd(int max_connections)
|
2020-09-24 23:26:57 +08:00
|
|
|
{
|
2022-05-12 08:49:23 +08:00
|
|
|
qemu_nbd_connections = max_connections;
|
2020-09-24 23:26:57 +08:00
|
|
|
}
|
|
|
|
|
2020-09-24 23:27:12 +08:00
|
|
|
bool nbd_server_is_running(void)
|
|
|
|
{
|
2022-05-12 08:49:23 +08:00
|
|
|
return nbd_server || qemu_nbd_connections >= 0;
|
2020-09-24 23:27:12 +08:00
|
|
|
}
|
|
|
|
|
nbd/server: Allow MULTI_CONN for shared writable exports
According to the NBD spec, a server that advertises
NBD_FLAG_CAN_MULTI_CONN promises that multiple client connections will
not see any cache inconsistencies: when properly separated by a single
flush, actions performed by one client will be visible to another
client, regardless of which client did the flush.
We always satisfy these conditions in qemu - even when we support
multiple clients, ALL clients go through a single point of reference
into the block layer, with no local caching. The effect of one client
is instantly visible to the next client. Even if our backend were a
network device, we argue that any multi-path caching effects that
would cause inconsistencies in back-to-back actions not seeing the
effect of previous actions would be a bug in that backend, and not the
fault of caching in qemu. As such, it is safe to unconditionally
advertise CAN_MULTI_CONN for any qemu NBD server situation that
supports parallel clients.
Note, however, that we don't want to advertise CAN_MULTI_CONN when we
know that a second client cannot connect (for historical reasons,
qemu-nbd defaults to a single connection while nbd-server-add and QMP
commands default to unlimited connections; but we already have
existing means to let either style of NBD server creation alter those
defaults). This is visible by no longer advertising MULTI_CONN for
'qemu-nbd -r' without -e, as in the iotest nbd-qemu-allocation.
The harder part of this patch is setting up an iotest to demonstrate
behavior of multiple NBD clients to a single server. It might be
possible with parallel qemu-io processes, but I found it easier to do
in python with the help of libnbd, and help from Nir and Vladimir in
writing the test.
Signed-off-by: Eric Blake <eblake@redhat.com>
Suggested-by: Nir Soffer <nsoffer@redhat.com>
Suggested-by: Vladimir Sementsov-Ogievskiy <v.sementsov-og@mail.ru>
Message-Id: <20220512004924.417153-3-eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2022-05-12 08:49:24 +08:00
|
|
|
int nbd_server_max_connections(void)
|
|
|
|
{
|
|
|
|
return nbd_server ? nbd_server->max_connections : qemu_nbd_connections;
|
|
|
|
}
|
|
|
|
|
nbd: Fix regression on resiliency to port scan
Back in qemu 2.5, qemu-nbd was immune to port probes (a transient
server would not quit, regardless of how many probe connections
came and went, until a connection actually negotiated). But we
broke that in commit ee7d7aa when removing the return value to
nbd_client_new(), although that patch also introduced a bug causing
an assertion failure on a client that fails negotiation. We then
made it worse during refactoring in commit 1a6245a (a segfault
before we could even assert); the (masked) assertion was cleaned
up in d3780c2 (still in 2.6), and just recently we finally fixed
the segfault ("nbd: Fully intialize client in case of failed
negotiation"). But that still means that ever since we added
TLS support to qemu-nbd, we have been vulnerable to an ill-timed
port-scan being able to cause a denial of service by taking down
qemu-nbd before a real client has a chance to connect.
Since negotiation is now handled asynchronously via coroutines,
we no longer have a synchronous point of return by re-adding a
return value to nbd_client_new(). So this patch instead wires
things up to pass the negotiation status through the close_fn
callback function.
Simple test across two terminals:
$ qemu-nbd -f raw -p 30001 file
$ nmap 127.0.0.1 -p 30001 && \
qemu-io -c 'r 0 512' -f raw nbd://localhost:30001
Note that this patch does not change what constitutes successful
negotiation (thus, a client must enter transmission phase before
that client can be considered as a reason to terminate the server
when the connection ends). Perhaps we may want to tweak things
in a later patch to also treat a client that uses NBD_OPT_ABORT
as being a 'successful' negotiation (the client correctly talked
the NBD protocol, and informed us it was not going to use our
export after all), but that's a discussion for another day.
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1451614
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20170608222617.20376-1-eblake@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-06-09 06:26:17 +08:00
|
|
|
static void nbd_blockdev_client_closed(NBDClient *client, bool ignored)
|
|
|
|
{
|
|
|
|
nbd_client_put(client);
|
2020-09-24 23:26:54 +08:00
|
|
|
assert(nbd_server->connections > 0);
|
|
|
|
nbd_server->connections--;
|
|
|
|
nbd_update_server_watch(nbd_server);
|
nbd: Fix regression on resiliency to port scan
Back in qemu 2.5, qemu-nbd was immune to port probes (a transient
server would not quit, regardless of how many probe connections
came and went, until a connection actually negotiated). But we
broke that in commit ee7d7aa when removing the return value to
nbd_client_new(), although that patch also introduced a bug causing
an assertion failure on a client that fails negotiation. We then
made it worse during refactoring in commit 1a6245a (a segfault
before we could even assert); the (masked) assertion was cleaned
up in d3780c2 (still in 2.6), and just recently we finally fixed
the segfault ("nbd: Fully intialize client in case of failed
negotiation"). But that still means that ever since we added
TLS support to qemu-nbd, we have been vulnerable to an ill-timed
port-scan being able to cause a denial of service by taking down
qemu-nbd before a real client has a chance to connect.
Since negotiation is now handled asynchronously via coroutines,
we no longer have a synchronous point of return by re-adding a
return value to nbd_client_new(). So this patch instead wires
things up to pass the negotiation status through the close_fn
callback function.
Simple test across two terminals:
$ qemu-nbd -f raw -p 30001 file
$ nmap 127.0.0.1 -p 30001 && \
qemu-io -c 'r 0 512' -f raw nbd://localhost:30001
Note that this patch does not change what constitutes successful
negotiation (thus, a client must enter transmission phase before
that client can be considered as a reason to terminate the server
when the connection ends). Perhaps we may want to tweak things
in a later patch to also treat a client that uses NBD_OPT_ABORT
as being a 'successful' negotiation (the client correctly talked
the NBD protocol, and informed us it was not going to use our
export after all), but that's a discussion for another day.
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1451614
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20170608222617.20376-1-eblake@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-06-09 06:26:17 +08:00
|
|
|
}
|
2012-08-22 22:43:07 +08:00
|
|
|
|
2017-12-18 18:16:42 +08:00
|
|
|
static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc,
|
|
|
|
gpointer opaque)
|
2012-08-22 22:43:07 +08:00
|
|
|
{
|
2020-09-24 23:26:54 +08:00
|
|
|
nbd_server->connections++;
|
|
|
|
nbd_update_server_watch(nbd_server);
|
|
|
|
|
2016-09-30 18:57:14 +08:00
|
|
|
qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server");
|
nbd: allow authorization with nbd-server-start QMP command
As with the previous patch to qemu-nbd, the nbd-server-start QMP command
also needs to be able to specify authorization when enabling TLS encryption.
First the client must create a QAuthZ object instance using the
'object-add' command:
{
'execute': 'object-add',
'arguments': {
'qom-type': 'authz-list',
'id': 'authz0',
'parameters': {
'policy': 'deny',
'rules': [
{
'match': '*CN=fred',
'policy': 'allow'
}
]
}
}
}
They can then reference this in the new 'tls-authz' parameter when
executing the 'nbd-server-start' command:
{
'execute': 'nbd-server-start',
'arguments': {
'addr': {
'type': 'inet',
'host': '127.0.0.1',
'port': '9000'
},
'tls-creds': 'tls0',
'tls-authz': 'authz0'
}
}
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <20190227162035.18543-3-berrange@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
2019-02-28 00:20:34 +08:00
|
|
|
nbd_client_new(cioc, nbd_server->tlscreds, nbd_server->tlsauthz,
|
nbd: Fix regression on resiliency to port scan
Back in qemu 2.5, qemu-nbd was immune to port probes (a transient
server would not quit, regardless of how many probe connections
came and went, until a connection actually negotiated). But we
broke that in commit ee7d7aa when removing the return value to
nbd_client_new(), although that patch also introduced a bug causing
an assertion failure on a client that fails negotiation. We then
made it worse during refactoring in commit 1a6245a (a segfault
before we could even assert); the (masked) assertion was cleaned
up in d3780c2 (still in 2.6), and just recently we finally fixed
the segfault ("nbd: Fully intialize client in case of failed
negotiation"). But that still means that ever since we added
TLS support to qemu-nbd, we have been vulnerable to an ill-timed
port-scan being able to cause a denial of service by taking down
qemu-nbd before a real client has a chance to connect.
Since negotiation is now handled asynchronously via coroutines,
we no longer have a synchronous point of return by re-adding a
return value to nbd_client_new(). So this patch instead wires
things up to pass the negotiation status through the close_fn
callback function.
Simple test across two terminals:
$ qemu-nbd -f raw -p 30001 file
$ nmap 127.0.0.1 -p 30001 && \
qemu-io -c 'r 0 512' -f raw nbd://localhost:30001
Note that this patch does not change what constitutes successful
negotiation (thus, a client must enter transmission phase before
that client can be considered as a reason to terminate the server
when the connection ends). Perhaps we may want to tweak things
in a later patch to also treat a client that uses NBD_OPT_ABORT
as being a 'successful' negotiation (the client correctly talked
the NBD protocol, and informed us it was not going to use our
export after all), but that's a discussion for another day.
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1451614
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20170608222617.20376-1-eblake@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-06-09 06:26:17 +08:00
|
|
|
nbd_blockdev_client_closed);
|
2012-08-22 22:43:07 +08:00
|
|
|
}
|
|
|
|
|
2020-09-24 23:26:54 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2016-02-11 02:41:14 +08:00
|
|
|
|
|
|
|
static void nbd_server_free(NBDServerData *server)
|
2012-08-22 22:43:07 +08:00
|
|
|
{
|
2016-02-11 02:41:14 +08:00
|
|
|
if (!server) {
|
2012-08-22 22:43:07 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-12-18 18:16:42 +08:00
|
|
|
qio_net_listener_disconnect(server->listener);
|
|
|
|
object_unref(OBJECT(server->listener));
|
2016-02-11 02:41:14 +08:00
|
|
|
if (server->tlscreds) {
|
|
|
|
object_unref(OBJECT(server->tlscreds));
|
|
|
|
}
|
nbd: allow authorization with nbd-server-start QMP command
As with the previous patch to qemu-nbd, the nbd-server-start QMP command
also needs to be able to specify authorization when enabling TLS encryption.
First the client must create a QAuthZ object instance using the
'object-add' command:
{
'execute': 'object-add',
'arguments': {
'qom-type': 'authz-list',
'id': 'authz0',
'parameters': {
'policy': 'deny',
'rules': [
{
'match': '*CN=fred',
'policy': 'allow'
}
]
}
}
}
They can then reference this in the new 'tls-authz' parameter when
executing the 'nbd-server-start' command:
{
'execute': 'nbd-server-start',
'arguments': {
'addr': {
'type': 'inet',
'host': '127.0.0.1',
'port': '9000'
},
'tls-creds': 'tls0',
'tls-authz': 'authz0'
}
}
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <20190227162035.18543-3-berrange@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
2019-02-28 00:20:34 +08:00
|
|
|
g_free(server->tlsauthz);
|
2016-02-11 02:41:14 +08:00
|
|
|
|
|
|
|
g_free(server);
|
|
|
|
}
|
|
|
|
|
|
|
|
static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)
|
|
|
|
{
|
|
|
|
Object *obj;
|
|
|
|
QCryptoTLSCreds *creds;
|
|
|
|
|
|
|
|
obj = object_resolve_path_component(
|
|
|
|
object_get_objects_root(), id);
|
|
|
|
if (!obj) {
|
|
|
|
error_setg(errp, "No TLS credentials with id '%s'",
|
|
|
|
id);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
creds = (QCryptoTLSCreds *)
|
|
|
|
object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS);
|
|
|
|
if (!creds) {
|
|
|
|
error_setg(errp, "Object with id '%s' is not TLS credentials",
|
|
|
|
id);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-06-29 00:09:09 +08:00
|
|
|
if (!qcrypto_tls_creds_check_endpoint(creds,
|
|
|
|
QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
|
|
|
|
errp)) {
|
2016-02-11 02:41:14 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
object_ref(obj);
|
|
|
|
return creds;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-26 15:36:41 +08:00
|
|
|
void nbd_server_start(SocketAddress *addr, const char *tls_creds,
|
2020-09-24 23:26:54 +08:00
|
|
|
const char *tls_authz, uint32_t max_connections,
|
|
|
|
Error **errp)
|
2016-02-11 02:41:14 +08:00
|
|
|
{
|
|
|
|
if (nbd_server) {
|
|
|
|
error_setg(errp, "NBD server already running");
|
2016-02-11 02:41:03 +08:00
|
|
|
return;
|
2012-08-22 22:43:07 +08:00
|
|
|
}
|
2016-02-11 02:41:03 +08:00
|
|
|
|
2016-02-11 02:41:14 +08:00
|
|
|
nbd_server = g_new0(NBDServerData, 1);
|
2020-09-24 23:26:54 +08:00
|
|
|
nbd_server->max_connections = max_connections;
|
2017-12-18 18:16:42 +08:00
|
|
|
nbd_server->listener = qio_net_listener_new();
|
|
|
|
|
|
|
|
qio_net_listener_set_name(nbd_server->listener,
|
|
|
|
"nbd-listener");
|
|
|
|
|
2021-02-09 23:27:58 +08:00
|
|
|
/*
|
|
|
|
* Because this server is persistent, a backlog of SOMAXCONN is
|
|
|
|
* better than trying to size it to max_connections.
|
|
|
|
*/
|
|
|
|
if (qio_net_listener_open_sync(nbd_server->listener, addr, SOMAXCONN,
|
|
|
|
errp) < 0) {
|
2016-02-11 02:41:14 +08:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2017-04-26 15:36:41 +08:00
|
|
|
if (tls_creds) {
|
2016-02-11 02:41:14 +08:00
|
|
|
nbd_server->tlscreds = nbd_get_tls_creds(tls_creds, errp);
|
|
|
|
if (!nbd_server->tlscreds) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
nbd: allow authorization with nbd-server-start QMP command
As with the previous patch to qemu-nbd, the nbd-server-start QMP command
also needs to be able to specify authorization when enabling TLS encryption.
First the client must create a QAuthZ object instance using the
'object-add' command:
{
'execute': 'object-add',
'arguments': {
'qom-type': 'authz-list',
'id': 'authz0',
'parameters': {
'policy': 'deny',
'rules': [
{
'match': '*CN=fred',
'policy': 'allow'
}
]
}
}
}
They can then reference this in the new 'tls-authz' parameter when
executing the 'nbd-server-start' command:
{
'execute': 'nbd-server-start',
'arguments': {
'addr': {
'type': 'inet',
'host': '127.0.0.1',
'port': '9000'
},
'tls-creds': 'tls0',
'tls-authz': 'authz0'
}
}
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <20190227162035.18543-3-berrange@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
2019-02-28 00:20:34 +08:00
|
|
|
nbd_server->tlsauthz = g_strdup(tls_authz);
|
|
|
|
|
2020-09-24 23:26:54 +08:00
|
|
|
nbd_update_server_watch(nbd_server);
|
2016-02-11 02:41:14 +08:00
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
|
|
|
nbd_server_free(nbd_server);
|
|
|
|
nbd_server = NULL;
|
2012-08-22 22:43:07 +08:00
|
|
|
}
|
|
|
|
|
2020-02-24 22:29:57 +08:00
|
|
|
void nbd_server_start_options(NbdServerOptions *arg, Error **errp)
|
|
|
|
{
|
2020-09-24 23:26:54 +08:00
|
|
|
nbd_server_start(arg->addr, arg->tls_creds, arg->tls_authz,
|
|
|
|
arg->max_connections, errp);
|
2020-02-24 22:29:57 +08:00
|
|
|
}
|
|
|
|
|
2017-04-26 15:36:41 +08:00
|
|
|
void qmp_nbd_server_start(SocketAddressLegacy *addr,
|
2022-11-05 00:06:52 +08:00
|
|
|
const char *tls_creds,
|
|
|
|
const char *tls_authz,
|
2020-09-24 23:26:54 +08:00
|
|
|
bool has_max_connections, uint32_t max_connections,
|
2017-04-26 15:36:41 +08:00
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
SocketAddress *addr_flat = socket_address_flatten(addr);
|
|
|
|
|
2020-09-24 23:26:54 +08:00
|
|
|
nbd_server_start(addr_flat, tls_creds, tls_authz, max_connections, errp);
|
2017-04-26 15:36:41 +08:00
|
|
|
qapi_free_SocketAddress(addr_flat);
|
|
|
|
}
|
|
|
|
|
2020-09-24 23:27:01 +08:00
|
|
|
void qmp_nbd_server_add(NbdServerAddOptions *arg, Error **errp)
|
2020-09-24 23:26:50 +08:00
|
|
|
{
|
2020-09-24 23:26:53 +08:00
|
|
|
BlockExport *export;
|
|
|
|
BlockDriverState *bs;
|
|
|
|
BlockBackend *on_eject_blk;
|
2020-09-24 23:27:01 +08:00
|
|
|
BlockExportOptions *export_opts;
|
2020-09-24 23:26:53 +08:00
|
|
|
|
|
|
|
bs = bdrv_lookup_bs(arg->device, arg->device, errp);
|
|
|
|
if (!bs) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-09-24 23:27:01 +08:00
|
|
|
/*
|
|
|
|
* block-export-add would default to the node-name, but we may have to use
|
|
|
|
* the device name as a default here for compatibility.
|
|
|
|
*/
|
2022-11-05 00:06:52 +08:00
|
|
|
if (!arg->name) {
|
2020-10-27 13:05:48 +08:00
|
|
|
arg->name = g_strdup(arg->device);
|
2020-09-24 23:27:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
export_opts = g_new(BlockExportOptions, 1);
|
|
|
|
*export_opts = (BlockExportOptions) {
|
|
|
|
.type = BLOCK_EXPORT_TYPE_NBD,
|
2020-09-24 23:27:04 +08:00
|
|
|
.id = g_strdup(arg->name),
|
2020-09-24 23:27:01 +08:00
|
|
|
.node_name = g_strdup(bdrv_get_node_name(bs)),
|
2020-09-24 23:27:11 +08:00
|
|
|
.has_writable = arg->has_writable,
|
|
|
|
.writable = arg->writable,
|
2020-09-24 23:26:50 +08:00
|
|
|
};
|
2020-10-27 13:05:49 +08:00
|
|
|
QAPI_CLONE_MEMBERS(BlockExportOptionsNbdBase, &export_opts->u.nbd,
|
2020-10-27 13:05:48 +08:00
|
|
|
qapi_NbdServerAddOptions_base(arg));
|
2022-11-05 00:06:52 +08:00
|
|
|
if (arg->bitmap) {
|
qapi: nbd-export: allow select bitmaps by node/name pair
Hi all! Current logic of relying on search through backing chain is not
safe neither convenient.
Sometimes it leads to necessity of extra bitmap copying. Also, we are
going to add "snapshot-access" driver, to access some snapshot state
through NBD. And this driver is not formally a filter, and of course
it's not a COW format driver. So, searching through backing chain will
not work. Instead of widening the workaround of bitmap searching, let's
extend the interface so that user can select bitmap precisely.
Note, that checking for bitmap active status is not copied to the new
API, I don't see a reason for it, user should understand the risks. And
anyway, bitmap from other node is unrelated to this export being
read-only or read-write.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@openvz.org>
Message-Id: <20220314213226.362217-3-v.sementsov-og@mail.ru>
[eblake: Adjust S-o-b to Vladimir's new email, with permission]
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
2022-03-15 05:32:25 +08:00
|
|
|
BlockDirtyBitmapOrStr *el = g_new(BlockDirtyBitmapOrStr, 1);
|
|
|
|
|
|
|
|
*el = (BlockDirtyBitmapOrStr) {
|
|
|
|
.type = QTYPE_QSTRING,
|
|
|
|
.u.local = g_strdup(arg->bitmap),
|
|
|
|
};
|
2020-10-27 13:05:49 +08:00
|
|
|
export_opts->u.nbd.has_bitmaps = true;
|
qapi: nbd-export: allow select bitmaps by node/name pair
Hi all! Current logic of relying on search through backing chain is not
safe neither convenient.
Sometimes it leads to necessity of extra bitmap copying. Also, we are
going to add "snapshot-access" driver, to access some snapshot state
through NBD. And this driver is not formally a filter, and of course
it's not a COW format driver. So, searching through backing chain will
not work. Instead of widening the workaround of bitmap searching, let's
extend the interface so that user can select bitmap precisely.
Note, that checking for bitmap active status is not copied to the new
API, I don't see a reason for it, user should understand the risks. And
anyway, bitmap from other node is unrelated to this export being
read-only or read-write.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@openvz.org>
Message-Id: <20220314213226.362217-3-v.sementsov-og@mail.ru>
[eblake: Adjust S-o-b to Vladimir's new email, with permission]
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
2022-03-15 05:32:25 +08:00
|
|
|
QAPI_LIST_PREPEND(export_opts->u.nbd.bitmaps, el);
|
2020-10-27 13:05:49 +08:00
|
|
|
}
|
2020-09-24 23:26:53 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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)) {
|
2020-09-24 23:27:11 +08:00
|
|
|
export_opts->has_writable = true;
|
|
|
|
export_opts->writable = false;
|
2020-09-24 23:26:53 +08:00
|
|
|
}
|
|
|
|
|
2020-09-24 23:27:01 +08:00
|
|
|
export = blk_exp_add(export_opts, errp);
|
2020-09-24 23:26:53 +08:00
|
|
|
if (!export) {
|
2020-09-24 23:27:01 +08:00
|
|
|
goto fail;
|
2020-09-24 23:26:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
}
|
2020-09-24 23:27:01 +08:00
|
|
|
|
|
|
|
fail:
|
|
|
|
qapi_free_BlockExportOptions(export_opts);
|
2012-08-22 22:43:07 +08:00
|
|
|
}
|
|
|
|
|
2018-01-19 21:57:16 +08:00
|
|
|
void qmp_nbd_server_remove(const char *name,
|
2020-09-24 23:27:06 +08:00
|
|
|
bool has_mode, BlockExportRemoveMode mode,
|
2018-01-19 21:57:16 +08:00
|
|
|
Error **errp)
|
|
|
|
{
|
2020-09-24 23:27:06 +08:00
|
|
|
BlockExport *exp;
|
2018-01-19 21:57:16 +08:00
|
|
|
|
2020-09-24 23:27:06 +08:00
|
|
|
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);
|
2018-01-19 21:57:16 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-09-24 23:27:06 +08:00
|
|
|
qmp_block_export_del(name, has_mode, mode, errp);
|
2018-01-19 21:57:16 +08:00
|
|
|
}
|
|
|
|
|
2012-08-22 22:43:07 +08:00
|
|
|
void qmp_nbd_server_stop(Error **errp)
|
|
|
|
{
|
2019-01-12 03:47:14 +08:00
|
|
|
if (!nbd_server) {
|
|
|
|
error_setg(errp, "NBD server not running");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-09-24 23:27:03 +08:00
|
|
|
blk_exp_close_all_type(BLOCK_EXPORT_TYPE_NBD);
|
2012-08-22 22:43:07 +08:00
|
|
|
|
2016-02-11 02:41:14 +08:00
|
|
|
nbd_server_free(nbd_server);
|
|
|
|
nbd_server = NULL;
|
2012-08-22 22:43:07 +08:00
|
|
|
}
|