block/nbd: bs-independent interface for nbd_co_establish_connection()

We are going to split connection code to a separate file. Now we are
ready to give nbd_co_establish_connection() clean and bs-independent
interface.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Roman Kagan <rvkagan@yandex-team.ru>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20210610100802.5888-13-vsementsov@virtuozzo.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
Vladimir Sementsov-Ogievskiy 2021-06-10 13:07:42 +03:00 committed by Eric Blake
parent b8e8a3d116
commit d33833d7af
1 changed files with 32 additions and 18 deletions

View File

@ -130,7 +130,8 @@ typedef struct BDRVNBDState {
static void nbd_free_connect_thread(NBDConnectThread *thr); static void nbd_free_connect_thread(NBDConnectThread *thr);
static int nbd_establish_connection(BlockDriverState *bs, SocketAddress *saddr, static int nbd_establish_connection(BlockDriverState *bs, SocketAddress *saddr,
Error **errp); Error **errp);
static int nbd_co_establish_connection(BlockDriverState *bs, Error **errp); static coroutine_fn QIOChannelSocket *
nbd_co_establish_connection(NBDConnectThread *thr, Error **errp);
static void nbd_co_establish_connection_cancel(BlockDriverState *bs); static void nbd_co_establish_connection_cancel(BlockDriverState *bs);
static int nbd_client_handshake(BlockDriverState *bs, Error **errp); static int nbd_client_handshake(BlockDriverState *bs, Error **errp);
static void nbd_yank(void *opaque); static void nbd_yank(void *opaque);
@ -416,22 +417,37 @@ static void *connect_thread_func(void *opaque)
return NULL; return NULL;
} }
static int coroutine_fn /*
nbd_co_establish_connection(BlockDriverState *bs, Error **errp) * Get a new connection in context of @thr:
* if the thread is running, wait for completion
* if the thread already succeeded in the background, and user didn't get the
* result, just return it now
* otherwise the thread is not running, so start a thread and wait for
* completion
*/
static coroutine_fn QIOChannelSocket *
nbd_co_establish_connection(NBDConnectThread *thr, Error **errp)
{ {
QIOChannelSocket *sioc = NULL;
QemuThread thread; QemuThread thread;
BDRVNBDState *s = bs->opaque;
NBDConnectThread *thr = s->connect_thread;
assert(!s->sioc);
qemu_mutex_lock(&thr->mutex); qemu_mutex_lock(&thr->mutex);
/*
* Don't call nbd_co_establish_connection() in several coroutines in
* parallel. Only one call at once is supported.
*/
assert(!thr->wait_co);
if (!thr->running) { if (!thr->running) {
if (thr->sioc) { if (thr->sioc) {
/* Previous attempt finally succeeded in background */ /* Previous attempt finally succeeded in background */
goto out; sioc = g_steal_pointer(&thr->sioc);
qemu_mutex_unlock(&thr->mutex);
return sioc;
} }
thr->running = true; thr->running = true;
error_free(thr->err); error_free(thr->err);
thr->err = NULL; thr->err = NULL;
@ -445,13 +461,12 @@ nbd_co_establish_connection(BlockDriverState *bs, Error **errp)
/* /*
* We are going to wait for connect-thread finish, but * We are going to wait for connect-thread finish, but
* nbd_client_co_drain_begin() can interrupt. * nbd_co_establish_connection_cancel() can interrupt.
*/ */
qemu_coroutine_yield(); qemu_coroutine_yield();
qemu_mutex_lock(&thr->mutex); qemu_mutex_lock(&thr->mutex);
out:
if (thr->running) { if (thr->running) {
/* /*
* The connection attempt was canceled and the coroutine resumed * The connection attempt was canceled and the coroutine resumed
@ -463,17 +478,12 @@ out:
} else { } else {
error_propagate(errp, thr->err); error_propagate(errp, thr->err);
thr->err = NULL; thr->err = NULL;
s->sioc = thr->sioc; sioc = g_steal_pointer(&thr->sioc);
thr->sioc = NULL;
if (s->sioc) {
yank_register_function(BLOCKDEV_YANK_INSTANCE(bs->node_name),
nbd_yank, bs);
}
} }
qemu_mutex_unlock(&thr->mutex); qemu_mutex_unlock(&thr->mutex);
return s->sioc ? 0 : -1; return sioc;
} }
/* /*
@ -541,11 +551,15 @@ static coroutine_fn void nbd_reconnect_attempt(BDRVNBDState *s)
s->ioc = NULL; s->ioc = NULL;
} }
if (nbd_co_establish_connection(s->bs, NULL) < 0) { s->sioc = nbd_co_establish_connection(s->connect_thread, NULL);
if (!s->sioc) {
ret = -ECONNREFUSED; ret = -ECONNREFUSED;
goto out; goto out;
} }
yank_register_function(BLOCKDEV_YANK_INSTANCE(s->bs->node_name), nbd_yank,
s->bs);
bdrv_dec_in_flight(s->bs); bdrv_dec_in_flight(s->bs);
ret = nbd_client_handshake(s->bs, NULL); ret = nbd_client_handshake(s->bs, NULL);