@@ -122,6 +122,8 @@ typedef struct BDRVNBDState {
Error *connect_err;
bool wait_in_flight;
+ QEMUTimer *reconnect_delay_timer;
+
NBDClientRequest requests[MAX_NBD_REQUESTS];
NBDReply reply;
BlockDriverState *bs;
@@ -188,10 +190,49 @@ static void nbd_recv_coroutines_wake_all(BDRVNBDState *s)
}
}
+static void reconnect_delay_timer_del(BDRVNBDState *s)
+{
+ if (s->reconnect_delay_timer) {
+ timer_del(s->reconnect_delay_timer);
+ timer_free(s->reconnect_delay_timer);
+ s->reconnect_delay_timer = NULL;
+ }
+}
+
+static void reconnect_delay_timer_cb(void *opaque)
+{
+ BDRVNBDState *s = opaque;
+
+ if (s->state == NBD_CLIENT_CONNECTING_WAIT) {
+ s->state = NBD_CLIENT_CONNECTING_NOWAIT;
+ while (qemu_co_enter_next(&s->free_sema, NULL)) {
+ /* Resume all queued requests */
+ }
+ }
+
+ reconnect_delay_timer_del(s);
+}
+
+static void reconnect_delay_timer_init(BDRVNBDState *s, uint64_t expire_time_ns)
+{
+ if (s->state != NBD_CLIENT_CONNECTING_WAIT) {
+ return;
+ }
+
+ assert(!s->reconnect_delay_timer);
+ s->reconnect_delay_timer = aio_timer_new(bdrv_get_aio_context(s->bs),
+ QEMU_CLOCK_REALTIME,
+ SCALE_NS,
+ reconnect_delay_timer_cb, s);
+ timer_mod(s->reconnect_delay_timer, expire_time_ns);
+}
+
static void nbd_client_detach_aio_context(BlockDriverState *bs)
{
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
+ /* Timer is deleted in nbd_client_co_drain_begin() */
+ assert(!s->reconnect_delay_timer);
qio_channel_detach_aio_context(QIO_CHANNEL(s->ioc));
}
@@ -243,6 +284,8 @@ static void coroutine_fn nbd_client_co_drain_begin(BlockDriverState *bs)
nbd_co_establish_connection_cancel(bs, false);
+ reconnect_delay_timer_del(s);
+
if (s->state == NBD_CLIENT_CONNECTING_WAIT) {
s->state = NBD_CLIENT_CONNECTING_NOWAIT;
qemu_co_queue_restart_all(&s->free_sema);
@@ -593,21 +636,17 @@ out:
static coroutine_fn void nbd_co_reconnect_loop(BDRVNBDState *s)
{
- uint64_t start_time_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
- uint64_t delay_ns = s->reconnect_delay * NANOSECONDS_PER_SECOND;
uint64_t timeout = 1 * NANOSECONDS_PER_SECOND;
uint64_t max_timeout = 16 * NANOSECONDS_PER_SECOND;
+ if (s->state == NBD_CLIENT_CONNECTING_WAIT) {
+ reconnect_delay_timer_init(s, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) +
+ s->reconnect_delay * NANOSECONDS_PER_SECOND);
+ }
+
nbd_reconnect_attempt(s);
while (nbd_client_connecting(s)) {
- if (s->state == NBD_CLIENT_CONNECTING_WAIT &&
- qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - start_time_ns > delay_ns)
- {
- s->state = NBD_CLIENT_CONNECTING_NOWAIT;
- qemu_co_queue_restart_all(&s->free_sema);
- }
-
if (s->drained) {
bdrv_dec_in_flight(s->bs);
s->wait_drained_end = true;
@@ -629,6 +668,8 @@ static coroutine_fn void nbd_co_reconnect_loop(BDRVNBDState *s)
nbd_reconnect_attempt(s);
}
+
+ reconnect_delay_timer_del(s);
}
static coroutine_fn void nbd_connection_entry(void *opaque)