summaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2012-03-05 09:10:35 +0100
committerPaolo Bonzini <pbonzini@redhat.com>2012-04-19 16:36:43 +0200
commit7fe7b68b32ba609faeeee03556aac0eb1b187c91 (patch)
tree87877a95bedeae58e0232c12459608b1bdb4128f /block
parent185b43386ad999c80bdc58e41b87f05e5b3e8463 (diff)
downloadqemu-7fe7b68b32ba609faeeee03556aac0eb1b187c91.tar.gz
qemu-7fe7b68b32ba609faeeee03556aac0eb1b187c91.tar.bz2
qemu-7fe7b68b32ba609faeeee03556aac0eb1b187c91.zip
nbd: do not block in nbd_wr_sync if no data at all is available
Right now, nbd_wr_sync will hang if no data at all is available on the socket and the other side is not going to provide any. Relax this by making it loop only for writes or partial reads. This fixes a race where one thread is executing qemu_aio_wait() and another is executing main_loop_wait(). Then, the select() call in main_loop_wait() can return stale data and call the "readable" callback with no data in the socket. Reported-by: Laurent Vivier <laurent@vivier.eu> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'block')
-rw-r--r--block/nbd.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/block/nbd.c b/block/nbd.c
index 1b0e384c39..e0af5b4725 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -151,10 +151,18 @@ static void nbd_reply_ready(void *opaque)
{
BDRVNBDState *s = opaque;
uint64_t i;
+ int ret;
if (s->reply.handle == 0) {
- /* No reply already in flight. Fetch a header. */
- if (nbd_receive_reply(s->sock, &s->reply) < 0) {
+ /* No reply already in flight. Fetch a header. It is possible
+ * that another thread has done the same thing in parallel, so
+ * the socket is not readable anymore.
+ */
+ ret = nbd_receive_reply(s->sock, &s->reply);
+ if (ret == -EAGAIN) {
+ return;
+ }
+ if (ret < 0) {
s->reply.handle = 0;
goto fail;
}