Skip to content

Commit

Permalink
nbd: allow reconnect on open, with corresponding new options
Browse files Browse the repository at this point in the history
It is useful when start of vm and start of nbd server are not
simple to sync.

Signed-off-by: Vladimir Sementsov-Ogievskiy <[email protected]>
Reviewed-by: Eric Blake <[email protected]>
  • Loading branch information
Vladimir Sementsov-Ogievskiy committed Dec 21, 2021
1 parent 2bf40d0 commit be16b8b
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 2 deletions.
45 changes: 44 additions & 1 deletion block/nbd.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,15 @@ typedef struct BDRVNBDState {
NBDClientState state;

QEMUTimer *reconnect_delay_timer;
QEMUTimer *open_timer;

NBDClientRequest requests[MAX_NBD_REQUESTS];
NBDReply reply;
BlockDriverState *bs;

/* Connection parameters */
uint32_t reconnect_delay;
uint32_t open_timeout;
SocketAddress *saddr;
char *export, *tlscredsid;
QCryptoTLSCreds *tlscreds;
Expand Down Expand Up @@ -218,6 +220,32 @@ static void nbd_teardown_connection(BlockDriverState *bs)
s->state = NBD_CLIENT_QUIT;
}

static void open_timer_del(BDRVNBDState *s)
{
if (s->open_timer) {
timer_free(s->open_timer);
s->open_timer = NULL;
}
}

static void open_timer_cb(void *opaque)
{
BDRVNBDState *s = opaque;

nbd_co_establish_connection_cancel(s->conn);
open_timer_del(s);
}

static void open_timer_init(BDRVNBDState *s, uint64_t expire_time_ns)
{
assert(!s->open_timer);
s->open_timer = aio_timer_new(bdrv_get_aio_context(s->bs),
QEMU_CLOCK_REALTIME,
SCALE_NS,
open_timer_cb, s);
timer_mod(s->open_timer, expire_time_ns);
}

static bool nbd_client_connecting(BDRVNBDState *s)
{
NBDClientState state = qatomic_load_acquire(&s->state);
Expand Down Expand Up @@ -1742,6 +1770,15 @@ static QemuOptsList nbd_runtime_opts = {
"future requests before a successful reconnect will "
"immediately fail. Default 0",
},
{
.name = "open-timeout",
.type = QEMU_OPT_NUMBER,
.help = "In seconds. If zero, the nbd driver tries the connection "
"only once, and fails to open if the connection fails. "
"If non-zero, the nbd driver will repeat connection "
"attempts until successful or until @open-timeout seconds "
"have elapsed. Default 0",
},
{ /* end of list */ }
},
};
Expand Down Expand Up @@ -1797,6 +1834,7 @@ static int nbd_process_options(BlockDriverState *bs, QDict *options,
}

s->reconnect_delay = qemu_opt_get_number(opts, "reconnect-delay", 0);
s->open_timeout = qemu_opt_get_number(opts, "open-timeout", 0);

ret = 0;

Expand Down Expand Up @@ -1828,7 +1866,12 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
s->conn = nbd_client_connection_new(s->saddr, true, s->export,
s->x_dirty_bitmap, s->tlscreds);

/* TODO: Configurable retry-until-timeout behaviour. */
if (s->open_timeout) {
nbd_client_connection_enable_retry(s->conn);
open_timer_init(s, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) +
s->open_timeout * NANOSECONDS_PER_SECOND);
}

s->state = NBD_CLIENT_CONNECTING_WAIT;
ret = nbd_do_establish_connection(bs, errp);
if (ret < 0) {
Expand Down
9 changes: 8 additions & 1 deletion qapi/block-core.json
Original file line number Diff line number Diff line change
Expand Up @@ -4096,6 +4096,12 @@
# future requests before a successful reconnect will
# immediately fail. Default 0 (Since 4.2)
#
# @open-timeout: In seconds. If zero, the nbd driver tries the connection
# only once, and fails to open if the connection fails.
# If non-zero, the nbd driver will repeat connection attempts
# until successful or until @open-timeout seconds have elapsed.
# Default 0 (Since 7.0)
#
# Features:
# @unstable: Member @x-dirty-bitmap is experimental.
#
Expand All @@ -4106,7 +4112,8 @@
'*export': 'str',
'*tls-creds': 'str',
'*x-dirty-bitmap': { 'type': 'str', 'features': [ 'unstable' ] },
'*reconnect-delay': 'uint32' } }
'*reconnect-delay': 'uint32',
'*open-timeout': 'uint32' } }

##
# @BlockdevOptionsRaw:
Expand Down

0 comments on commit be16b8b

Please sign in to comment.