Although most of our synchronous commands are fine doing a round-robin for the first ready connection, and will leave the connection back in the ready state on conclusion, shutdown is a different beast. Once handshake has finished, we want a shutdown request to reach all connections, even if it has to be queued behind other commands already being processed on that connection. In the future, we may want to consider a flags argument on whether to wait for the connection to have no in-flight commands, and/or to force a disconnect request to the front of the queue of commands to issue, depending on whether the client wants a fast shutdown vs. completion of outstanding requests to avoid data corruption. The NBD spec recommends that NBD_CMD_DISC not be sent while any other commands are in flight, but similarly that a server should not shut down due to NBD_CMD_DISC until all other responses have been flushed. We may also want to update the state machine to track that once NBD_CMD_DISC has been sent, it is not valid to queue or send any further commands on that connection, even if it is still up to receive replies to previous in-flight commands. --- lib/disconnect.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/disconnect.c b/lib/disconnect.c index 9706835..0b8fea0 100644 --- a/lib/disconnect.c +++ b/lib/disconnect.c @@ -31,7 +31,8 @@ nbd_unlocked_shutdown (struct nbd_handle *h) size_t i; for (i = 0; i < h->multi_conn; ++i) { - if (nbd_unlocked_aio_is_ready (h->conns[i])) { + if (nbd_unlocked_aio_is_ready (h->conns[i]) || + nbd_unlocked_aio_is_processing (h->conns[i])) { if (nbd_unlocked_aio_disconnect (h->conns[i]) == -1) return -1; } -- 2.20.1