nbd/client-connection: implement connection retry
Add an option for a thread to retry connecting until it succeeds. We'll use nbd/client-connection both for reconnect and for initial connection in nbd_open(), so we need a possibility to use same NBDClientConnection instance to connect once in nbd_open() and then use retry semantics for reconnect. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Message-Id: <20210610100802.5888-21-vsementsov@virtuozzo.com> Reviewed-by: Eric Blake <eblake@redhat.com> [eblake: grammar tweak] Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
parent
130d49baa5
commit
e0e67cbe58
@ -409,6 +409,8 @@ const char *nbd_err_lookup(int err);
|
|||||||
/* nbd/client-connection.c */
|
/* nbd/client-connection.c */
|
||||||
typedef struct NBDClientConnection NBDClientConnection;
|
typedef struct NBDClientConnection NBDClientConnection;
|
||||||
|
|
||||||
|
void nbd_client_connection_enable_retry(NBDClientConnection *conn);
|
||||||
|
|
||||||
NBDClientConnection *nbd_client_connection_new(const SocketAddress *saddr,
|
NBDClientConnection *nbd_client_connection_new(const SocketAddress *saddr,
|
||||||
bool do_negotiation,
|
bool do_negotiation,
|
||||||
const char *export_name,
|
const char *export_name,
|
||||||
|
@ -35,6 +35,7 @@ struct NBDClientConnection {
|
|||||||
QCryptoTLSCreds *tlscreds;
|
QCryptoTLSCreds *tlscreds;
|
||||||
NBDExportInfo initial_info;
|
NBDExportInfo initial_info;
|
||||||
bool do_negotiation;
|
bool do_negotiation;
|
||||||
|
bool do_retry;
|
||||||
|
|
||||||
QemuMutex mutex;
|
QemuMutex mutex;
|
||||||
|
|
||||||
@ -61,6 +62,15 @@ struct NBDClientConnection {
|
|||||||
Coroutine *wait_co;
|
Coroutine *wait_co;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The function isn't protected by any mutex, only call it when the client
|
||||||
|
* connection attempt has not yet started.
|
||||||
|
*/
|
||||||
|
void nbd_client_connection_enable_retry(NBDClientConnection *conn)
|
||||||
|
{
|
||||||
|
conn->do_retry = true;
|
||||||
|
}
|
||||||
|
|
||||||
NBDClientConnection *nbd_client_connection_new(const SocketAddress *saddr,
|
NBDClientConnection *nbd_client_connection_new(const SocketAddress *saddr,
|
||||||
bool do_negotiation,
|
bool do_negotiation,
|
||||||
const char *export_name,
|
const char *export_name,
|
||||||
@ -155,24 +165,44 @@ static void *connect_thread_func(void *opaque)
|
|||||||
NBDClientConnection *conn = opaque;
|
NBDClientConnection *conn = opaque;
|
||||||
int ret;
|
int ret;
|
||||||
bool do_free;
|
bool do_free;
|
||||||
|
uint64_t timeout = 1;
|
||||||
|
uint64_t max_timeout = 16;
|
||||||
|
|
||||||
conn->sioc = qio_channel_socket_new();
|
while (true) {
|
||||||
|
conn->sioc = qio_channel_socket_new();
|
||||||
|
|
||||||
error_free(conn->err);
|
error_free(conn->err);
|
||||||
conn->err = NULL;
|
conn->err = NULL;
|
||||||
conn->updated_info = conn->initial_info;
|
conn->updated_info = conn->initial_info;
|
||||||
|
|
||||||
ret = nbd_connect(conn->sioc, conn->saddr,
|
ret = nbd_connect(conn->sioc, conn->saddr,
|
||||||
conn->do_negotiation ? &conn->updated_info : NULL,
|
conn->do_negotiation ? &conn->updated_info : NULL,
|
||||||
conn->tlscreds, &conn->ioc, &conn->err);
|
conn->tlscreds, &conn->ioc, &conn->err);
|
||||||
if (ret < 0) {
|
|
||||||
object_unref(OBJECT(conn->sioc));
|
/*
|
||||||
conn->sioc = NULL;
|
* conn->updated_info will finally be returned to the user. Clear the
|
||||||
|
* pointers to our internally allocated strings, which are IN parameters
|
||||||
|
* of nbd_receive_negotiate() and therefore nbd_connect(). Caller
|
||||||
|
* shoudn't be interested in these fields.
|
||||||
|
*/
|
||||||
|
conn->updated_info.x_dirty_bitmap = NULL;
|
||||||
|
conn->updated_info.name = NULL;
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
object_unref(OBJECT(conn->sioc));
|
||||||
|
conn->sioc = NULL;
|
||||||
|
if (conn->do_retry) {
|
||||||
|
sleep(timeout);
|
||||||
|
if (timeout < max_timeout) {
|
||||||
|
timeout *= 2;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn->updated_info.x_dirty_bitmap = NULL;
|
|
||||||
conn->updated_info.name = NULL;
|
|
||||||
|
|
||||||
qemu_mutex_lock(&conn->mutex);
|
qemu_mutex_lock(&conn->mutex);
|
||||||
|
|
||||||
assert(conn->running);
|
assert(conn->running);
|
||||||
|
Loading…
Reference in New Issue
Block a user