[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 2/3] block/nbd: on shutdown terminate connection attempt
From: |
Vladimir Sementsov-Ogievskiy |
Subject: |
[PATCH 2/3] block/nbd: on shutdown terminate connection attempt |
Date: |
Mon, 20 Jul 2020 12:00:23 +0300 |
On shutdown nbd driver may be in a connecting state. We should shutdown
it as well, otherwise we may hang in
nbd_teardown_connection, waiting for conneciton_co to finish in
BDRV_POLL_WHILE(bs, s->connection_co) loop if remote server is down.
How to reproduce the dead lock:
1. Create nbd-fault-injector.conf with the following contents:
[inject-error "mega1"]
event=data
io=readwrite
when=before
2. In one terminal run nbd-fault-injector in a loop, like this:
n=1; while true; do
echo $n; ((n++));
./nbd-fault-injector.py 127.0.0.1:10000 nbd-fault-injector.conf;
done
3. In another terminal run qemu-io in a loop, like this:
n=1; while true; do
echo $n; ((n++));
./qemu-io -c 'read 0 512' nbd+tcp://127.0.0.1:10000;
done
After some time, qemu-io will hang. Note, that this hang may be
triggered by another bug, so the whole case is fixed only together with
commit "block/nbd: allow drain during reconnect attempt".
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
block/nbd.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/block/nbd.c b/block/nbd.c
index 49254f1c3c..42146a26f7 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -206,11 +206,15 @@ static void nbd_teardown_connection(BlockDriverState *bs)
{
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
- if (s->state == NBD_CLIENT_CONNECTED) {
+ if (s->ioc) {
/* finish any pending coroutines */
- assert(s->ioc);
qio_channel_shutdown(s->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
+ } else if (s->sioc) {
+ /* abort negotiation */
+ qio_channel_shutdown(QIO_CHANNEL(s->sioc), QIO_CHANNEL_SHUTDOWN_BOTH,
+ NULL);
}
+
s->state = NBD_CLIENT_QUIT;
if (s->connection_co) {
if (s->connection_co_sleep_ns_state) {
@@ -1452,6 +1456,8 @@ static int nbd_client_connect(BlockDriverState *bs, Error
**errp)
return -ECONNREFUSED;
}
+ s->sioc = sioc;
+
/* NBD handshake */
trace_nbd_client_connect(s->export);
qio_channel_set_blocking(QIO_CHANNEL(sioc), false, NULL);
@@ -1468,6 +1474,7 @@ static int nbd_client_connect(BlockDriverState *bs, Error
**errp)
g_free(s->info.name);
if (ret < 0) {
object_unref(OBJECT(sioc));
+ s->sioc = NULL;
return ret;
}
if (s->x_dirty_bitmap && !s->info.base_allocation) {
@@ -1493,8 +1500,6 @@ static int nbd_client_connect(BlockDriverState *bs, Error
**errp)
}
}
- s->sioc = sioc;
-
if (!s->ioc) {
s->ioc = QIO_CHANNEL(sioc);
object_ref(OBJECT(s->ioc));
@@ -1515,6 +1520,7 @@ static int nbd_client_connect(BlockDriverState *bs, Error
**errp)
nbd_send_request(s->ioc ?: QIO_CHANNEL(sioc), &request);
object_unref(OBJECT(sioc));
+ s->sioc = NULL;
return ret;
}
--
2.21.0