From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
To: qemu-block@nongnu.org
Cc: qemu-devel@nongnu.org, mreitz@redhat.com, kwolf@redhat.com,
eblake@redhat.com, vsementsov@virtuozzo.com, den@openvz.org
Subject: [PATCH 3/4] block/nbd: fix reconnect-delay
Date: Thu, 3 Sep 2020 22:03:00 +0300 [thread overview]
Message-ID: <20200903190301.367620-4-vsementsov@virtuozzo.com> (raw)
In-Reply-To: <20200903190301.367620-1-vsementsov@virtuozzo.com>
reconnect-delay has a design flaw: we handle it in the same loop where
we do connection attempt. So, reconnect-delay may be exceeded by
unpredictable time of connection attempt.
Let's instead use separate timer.
How to reproduce the bug:
1. Create an image on node1:
qemu-img create -f qcow2 xx 100M
2. Start NBD server on node1:
qemu-nbd xx
3. On node2 start qemu-io:
./build/qemu-io --image-opts \
driver=nbd,server.type=inet,server.host=192.168.100.5,server.port=10809,reconnect-delay=15
4. Type 'read 0 512' in qemu-io interface to check that connection
works
Be careful: you should make steps 5-7 in a short time, less than 15
seconds.
5. Kill nbd server on node1
6. Run 'read 0 512' in qemu-io interface again, to be sure that nbd
client goes to reconnect loop.
7. On node1 run the following command
sudo iptables -A INPUT -p tcp --dport 10809 -j DROP
This will make the connect() call of qemu-io at node2 take a long time.
And you'll see that read command in qemu-io will hang for a long time,
more than 15 seconds specified by reconnect-delay parameter. It's the
bug.
8. Don't forget to drop iptables rule on node1:
sudo iptables -D INPUT -p tcp --dport 10809 -j DROP
Important note: Step [5] is necessary to reproduce _this_ bug. If we
miss step [5], the read command (step 6) will hang for a long time and
this commit doesn't help, because there will be not long connect() to
unreachable host, but long sendmsg() to unreachable host, which should
be fixed by enabling and adjusting keep-alive on the socket, which is a
thing for further patch set.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
block/nbd.c | 59 +++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 50 insertions(+), 9 deletions(-)
diff --git a/block/nbd.c b/block/nbd.c
index a495ad7ddf..caae0e6d31 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -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)
--
2.18.0
next prev parent reply other threads:[~2020-09-03 19:07 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-09-03 19:02 [PATCH 0/4] nbd reconnect new fixes Vladimir Sementsov-Ogievskiy
2020-09-03 19:02 ` [PATCH 1/4] block/nbd: fix drain dead-lock because of nbd reconnect-delay Vladimir Sementsov-Ogievskiy
2020-09-23 15:08 ` Eric Blake
2021-02-03 10:53 ` Roman Kagan
2021-02-03 13:10 ` Vladimir Sementsov-Ogievskiy
2021-02-03 14:21 ` Roman Kagan
2021-02-03 14:44 ` Vladimir Sementsov-Ogievskiy
2021-02-03 15:00 ` Roman Kagan
2020-09-03 19:02 ` [PATCH 2/4] block/nbd: correctly use qio_channel_detach_aio_context when needed Vladimir Sementsov-Ogievskiy
2020-09-23 15:10 ` Eric Blake
2020-09-03 19:03 ` Vladimir Sementsov-Ogievskiy [this message]
2020-09-23 15:15 ` [PATCH 3/4] block/nbd: fix reconnect-delay Eric Blake
2020-09-03 19:03 ` [PATCH 4/4] block/nbd: nbd_co_reconnect_loop(): don't connect if drained Vladimir Sementsov-Ogievskiy
2020-09-23 15:16 ` Eric Blake
2020-09-04 13:32 ` [PATCH 0/4] nbd reconnect new fixes no-reply
2020-09-04 14:00 ` Vladimir Sementsov-Ogievskiy
2020-09-04 13:34 ` no-reply
2020-09-04 14:01 ` Vladimir Sementsov-Ogievskiy
2020-09-18 18:29 ` Vladimir Sementsov-Ogievskiy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200903190301.367620-4-vsementsov@virtuozzo.com \
--to=vsementsov@virtuozzo.com \
--cc=den@openvz.org \
--cc=eblake@redhat.com \
--cc=kwolf@redhat.com \
--cc=mreitz@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).