mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 16:23:55 -06:00
nbd/client-connection: add possibility of negotiation
Add arguments and logic to support nbd negotiation in the same thread after successful connection. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Message-Id: <20210610100802.5888-20-vsementsov@virtuozzo.com> Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
parent
e70da5ff64
commit
130d49baa5
3 changed files with 109 additions and 9 deletions
|
@ -357,7 +357,7 @@ static coroutine_fn void nbd_reconnect_attempt(BDRVNBDState *s)
|
||||||
s->ioc = NULL;
|
s->ioc = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->sioc = nbd_co_establish_connection(s->conn, NULL);
|
s->sioc = nbd_co_establish_connection(s->conn, NULL, NULL, NULL);
|
||||||
if (!s->sioc) {
|
if (!s->sioc) {
|
||||||
ret = -ECONNREFUSED;
|
ret = -ECONNREFUSED;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -2035,7 +2035,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->conn = nbd_client_connection_new(s->saddr);
|
s->conn = nbd_client_connection_new(s->saddr, false, NULL, NULL, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* establish TCP connection, return error if it fails
|
* establish TCP connection, return error if it fails
|
||||||
|
|
|
@ -409,11 +409,16 @@ const char *nbd_err_lookup(int err);
|
||||||
/* nbd/client-connection.c */
|
/* nbd/client-connection.c */
|
||||||
typedef struct NBDClientConnection NBDClientConnection;
|
typedef struct NBDClientConnection NBDClientConnection;
|
||||||
|
|
||||||
NBDClientConnection *nbd_client_connection_new(const SocketAddress *saddr);
|
NBDClientConnection *nbd_client_connection_new(const SocketAddress *saddr,
|
||||||
|
bool do_negotiation,
|
||||||
|
const char *export_name,
|
||||||
|
const char *x_dirty_bitmap,
|
||||||
|
QCryptoTLSCreds *tlscreds);
|
||||||
void nbd_client_connection_release(NBDClientConnection *conn);
|
void nbd_client_connection_release(NBDClientConnection *conn);
|
||||||
|
|
||||||
QIOChannelSocket *coroutine_fn
|
QIOChannelSocket *coroutine_fn
|
||||||
nbd_co_establish_connection(NBDClientConnection *conn, Error **errp);
|
nbd_co_establish_connection(NBDClientConnection *conn, NBDExportInfo *info,
|
||||||
|
QIOChannel **ioc, Error **errp);
|
||||||
|
|
||||||
void coroutine_fn nbd_co_establish_connection_cancel(NBDClientConnection *conn);
|
void coroutine_fn nbd_co_establish_connection_cancel(NBDClientConnection *conn);
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,11 @@
|
||||||
#include "qapi/clone-visitor.h"
|
#include "qapi/clone-visitor.h"
|
||||||
|
|
||||||
struct NBDClientConnection {
|
struct NBDClientConnection {
|
||||||
/* Initialization constants */
|
/* Initialization constants, never change */
|
||||||
SocketAddress *saddr; /* address to connect to */
|
SocketAddress *saddr; /* address to connect to */
|
||||||
|
QCryptoTLSCreds *tlscreds;
|
||||||
|
NBDExportInfo initial_info;
|
||||||
|
bool do_negotiation;
|
||||||
|
|
||||||
QemuMutex mutex;
|
QemuMutex mutex;
|
||||||
|
|
||||||
|
@ -42,7 +45,9 @@ struct NBDClientConnection {
|
||||||
* nbd_co_establish_connection then steals these pointers while
|
* nbd_co_establish_connection then steals these pointers while
|
||||||
* under the mutex.
|
* under the mutex.
|
||||||
*/
|
*/
|
||||||
|
NBDExportInfo updated_info;
|
||||||
QIOChannelSocket *sioc;
|
QIOChannelSocket *sioc;
|
||||||
|
QIOChannel *ioc;
|
||||||
Error *err;
|
Error *err;
|
||||||
|
|
||||||
/* All further fields are accessed only under mutex */
|
/* All further fields are accessed only under mutex */
|
||||||
|
@ -56,12 +61,25 @@ struct NBDClientConnection {
|
||||||
Coroutine *wait_co;
|
Coroutine *wait_co;
|
||||||
};
|
};
|
||||||
|
|
||||||
NBDClientConnection *nbd_client_connection_new(const SocketAddress *saddr)
|
NBDClientConnection *nbd_client_connection_new(const SocketAddress *saddr,
|
||||||
|
bool do_negotiation,
|
||||||
|
const char *export_name,
|
||||||
|
const char *x_dirty_bitmap,
|
||||||
|
QCryptoTLSCreds *tlscreds)
|
||||||
{
|
{
|
||||||
NBDClientConnection *conn = g_new(NBDClientConnection, 1);
|
NBDClientConnection *conn = g_new(NBDClientConnection, 1);
|
||||||
|
|
||||||
|
object_ref(OBJECT(tlscreds));
|
||||||
*conn = (NBDClientConnection) {
|
*conn = (NBDClientConnection) {
|
||||||
.saddr = QAPI_CLONE(SocketAddress, saddr),
|
.saddr = QAPI_CLONE(SocketAddress, saddr),
|
||||||
|
.tlscreds = tlscreds,
|
||||||
|
.do_negotiation = do_negotiation,
|
||||||
|
|
||||||
|
.initial_info.request_sizes = true,
|
||||||
|
.initial_info.structured_reply = true,
|
||||||
|
.initial_info.base_allocation = true,
|
||||||
|
.initial_info.x_dirty_bitmap = g_strdup(x_dirty_bitmap),
|
||||||
|
.initial_info.name = g_strdup(export_name ?: "")
|
||||||
};
|
};
|
||||||
|
|
||||||
qemu_mutex_init(&conn->mutex);
|
qemu_mutex_init(&conn->mutex);
|
||||||
|
@ -77,9 +95,61 @@ static void nbd_client_connection_do_free(NBDClientConnection *conn)
|
||||||
}
|
}
|
||||||
error_free(conn->err);
|
error_free(conn->err);
|
||||||
qapi_free_SocketAddress(conn->saddr);
|
qapi_free_SocketAddress(conn->saddr);
|
||||||
|
object_unref(OBJECT(conn->tlscreds));
|
||||||
|
g_free(conn->initial_info.x_dirty_bitmap);
|
||||||
|
g_free(conn->initial_info.name);
|
||||||
g_free(conn);
|
g_free(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Connect to @addr and do NBD negotiation if @info is not null. If @tlscreds
|
||||||
|
* are given @outioc is returned. @outioc is provided only on success. The call
|
||||||
|
* may be cancelled from other thread by simply qio_channel_shutdown(sioc).
|
||||||
|
*/
|
||||||
|
static int nbd_connect(QIOChannelSocket *sioc, SocketAddress *addr,
|
||||||
|
NBDExportInfo *info, QCryptoTLSCreds *tlscreds,
|
||||||
|
QIOChannel **outioc, Error **errp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (outioc) {
|
||||||
|
*outioc = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = qio_channel_socket_connect_sync(sioc, addr, errp);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
qio_channel_set_delay(QIO_CHANNEL(sioc), false);
|
||||||
|
|
||||||
|
if (!info) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nbd_receive_negotiate(NULL, QIO_CHANNEL(sioc), tlscreds,
|
||||||
|
tlscreds ? addr->u.inet.host : NULL,
|
||||||
|
outioc, info, errp);
|
||||||
|
if (ret < 0) {
|
||||||
|
/*
|
||||||
|
* nbd_receive_negotiate() may setup tls ioc and return it even on
|
||||||
|
* failure path. In this case we should use it instead of original
|
||||||
|
* channel.
|
||||||
|
*/
|
||||||
|
if (outioc && *outioc) {
|
||||||
|
qio_channel_close(QIO_CHANNEL(*outioc), NULL);
|
||||||
|
object_unref(OBJECT(*outioc));
|
||||||
|
*outioc = NULL;
|
||||||
|
} else {
|
||||||
|
qio_channel_close(QIO_CHANNEL(sioc), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void *connect_thread_func(void *opaque)
|
static void *connect_thread_func(void *opaque)
|
||||||
{
|
{
|
||||||
NBDClientConnection *conn = opaque;
|
NBDClientConnection *conn = opaque;
|
||||||
|
@ -90,13 +160,18 @@ static void *connect_thread_func(void *opaque)
|
||||||
|
|
||||||
error_free(conn->err);
|
error_free(conn->err);
|
||||||
conn->err = NULL;
|
conn->err = NULL;
|
||||||
ret = qio_channel_socket_connect_sync(conn->sioc, conn->saddr, &conn->err);
|
conn->updated_info = conn->initial_info;
|
||||||
|
|
||||||
|
ret = nbd_connect(conn->sioc, conn->saddr,
|
||||||
|
conn->do_negotiation ? &conn->updated_info : NULL,
|
||||||
|
conn->tlscreds, &conn->ioc, &conn->err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
object_unref(OBJECT(conn->sioc));
|
object_unref(OBJECT(conn->sioc));
|
||||||
conn->sioc = NULL;
|
conn->sioc = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
qio_channel_set_delay(QIO_CHANNEL(conn->sioc), false);
|
conn->updated_info.x_dirty_bitmap = NULL;
|
||||||
|
conn->updated_info.name = NULL;
|
||||||
|
|
||||||
qemu_mutex_lock(&conn->mutex);
|
qemu_mutex_lock(&conn->mutex);
|
||||||
|
|
||||||
|
@ -146,12 +221,24 @@ void nbd_client_connection_release(NBDClientConnection *conn)
|
||||||
* result, just return it now
|
* result, just return it now
|
||||||
* otherwise the thread is not running, so start a thread and wait for
|
* otherwise the thread is not running, so start a thread and wait for
|
||||||
* completion
|
* completion
|
||||||
|
*
|
||||||
|
* If @info is not NULL, also do nbd-negotiation after successful connection.
|
||||||
|
* In this case info is used only as out parameter, and is fully initialized by
|
||||||
|
* nbd_co_establish_connection(). "IN" fields of info as well as related only to
|
||||||
|
* nbd_receive_export_list() would be zero (see description of NBDExportInfo in
|
||||||
|
* include/block/nbd.h).
|
||||||
*/
|
*/
|
||||||
QIOChannelSocket *coroutine_fn
|
QIOChannelSocket *coroutine_fn
|
||||||
nbd_co_establish_connection(NBDClientConnection *conn, Error **errp)
|
nbd_co_establish_connection(NBDClientConnection *conn, NBDExportInfo *info,
|
||||||
|
QIOChannel **ioc, Error **errp)
|
||||||
{
|
{
|
||||||
QemuThread thread;
|
QemuThread thread;
|
||||||
|
|
||||||
|
if (conn->do_negotiation) {
|
||||||
|
assert(info);
|
||||||
|
assert(ioc);
|
||||||
|
}
|
||||||
|
|
||||||
WITH_QEMU_LOCK_GUARD(&conn->mutex) {
|
WITH_QEMU_LOCK_GUARD(&conn->mutex) {
|
||||||
/*
|
/*
|
||||||
* Don't call nbd_co_establish_connection() in several coroutines in
|
* Don't call nbd_co_establish_connection() in several coroutines in
|
||||||
|
@ -162,6 +249,10 @@ nbd_co_establish_connection(NBDClientConnection *conn, Error **errp)
|
||||||
if (!conn->running) {
|
if (!conn->running) {
|
||||||
if (conn->sioc) {
|
if (conn->sioc) {
|
||||||
/* Previous attempt finally succeeded in background */
|
/* Previous attempt finally succeeded in background */
|
||||||
|
if (conn->do_negotiation) {
|
||||||
|
*ioc = g_steal_pointer(&conn->ioc);
|
||||||
|
memcpy(info, &conn->updated_info, sizeof(*info));
|
||||||
|
}
|
||||||
return g_steal_pointer(&conn->sioc);
|
return g_steal_pointer(&conn->sioc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,6 +285,10 @@ nbd_co_establish_connection(NBDClientConnection *conn, Error **errp)
|
||||||
} else {
|
} else {
|
||||||
error_propagate(errp, conn->err);
|
error_propagate(errp, conn->err);
|
||||||
conn->err = NULL;
|
conn->err = NULL;
|
||||||
|
if (conn->sioc && conn->do_negotiation) {
|
||||||
|
*ioc = g_steal_pointer(&conn->ioc);
|
||||||
|
memcpy(info, &conn->updated_info, sizeof(*info));
|
||||||
|
}
|
||||||
return g_steal_pointer(&conn->sioc);
|
return g_steal_pointer(&conn->sioc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue