@@ -36,6 +36,10 @@ ssize_t nbd_rwv(QIOChannel *ioc, struct iovec *iov,
size_t niov, size_t length,
while (nlocal_iov > 0) {
ssize_t len;
+ static int hack;
+ if (hack) {
+ len = QIO_CHANNEL_ERR_BLOCK;
+ } else
if (do_read) {
len = qio_channel_readv(ioc, local_iov, nlocal_iov, errp);
} else {
I was able to set a breakpoint in gdb to temporarily manipulate 'hack'
at the right moment, in order to trigger what would happen if a
nbd_rwv() hit EAGAIN. And sadly, I got a segfault using my patches,
because the last reference to ioc had been cleared in the meantime.
Program received signal SIGSEGV, Segmentation fault.
0x000055555562ee94 in object_class_dynamic_cast_assert
(class=0x555555d9d1b0,
typename=0x5555556c856d "qio-channel", file=0x5555556c8560
"io/channel.c",
line=75, func=0x5555556c8670 <__func__.21506> "qio_channel_writev_full")
at qom/object.c:705
705 trace_object_class_dynamic_cast_assert(class ? class->type->name
: "(null)",
#0 0x000055555562ee94 in object_class_dynamic_cast_assert (
class=0x555555d9d1b0, typename=0x5555556c856d "qio-channel",
file=0x5555556c8560 "io/channel.c", line=75,
func=0x5555556c8670 <__func__.21506> "qio_channel_writev_full")
at qom/object.c:705
#1 0x000055555562312d in qio_channel_writev_full (ioc=0x555555d9bde0,
iov=0x555555d9ec90, niov=1, fds=0x0, nfds=0, errp=0x0) at
io/channel.c:75
#2 0x0000555555623233 in qio_channel_writev (ioc=0x555555d9bde0,
iov=0x555555d9ec90, niov=1, errp=0x0) at io/channel.c:102
#3 0x0000555555603590 in nbd_rwv (ioc=0x555555d9bde0, iov=0x555555d9ecd0,
niov=1, length=1048576, do_read=false, errp=0x0) at nbd/common.c:46
#4 0x00005555555ebcca in nbd_co_send_request (bs=0x555555d94260,
request=0x7fffda2819f0, qiov=0x555555d9ee88) at block/nbd-client.c:152
My next test is whether incrementing the ref-count to s->ioc for the
duration of nbd_co_send_request() is adequate to protect against this
problem:
@@ -147,6 +147,11 @@ static int nbd_co_send_request(BlockDriverState *bs,
return -EPIPE;
}
+ /*
+ * Make sure ioc stays live, even if another coroutine decides to
+ * kill the connection because of a server error.
+ */
+ object_ref(OBJECT(ioc));
if (qiov) {
qio_channel_set_cork(ioc, true);
rc = nbd_send_request(ioc, request);
@@ -161,6 +166,7 @@ static int nbd_co_send_request(BlockDriverState *bs,
} else {
rc = nbd_send_request(ioc, request);
}
+ object_unref(OBJECT(ioc));
qemu_co_mutex_unlock(&s->send_mutex);
return rc;
}