Skip to content

Commit 7e60746

Browse files
jmberg-intelrichardweinberger
authored andcommitted
um: virtio: Keep reading on -EAGAIN
When we get an interrupt from the socket getting readable, and start reading, there's a possibility for a race. This depends on the implementation of the device, but e.g. with qemu's libvhost-user, we can see: device virtio_uml --------------------------------------- write header get interrupt read header read body -> returns -EAGAIN write body The -EAGAIN return is because the socket is non-blocking, and then this leads us to abandon this message. In fact, we've already read the header, so when the get another signal/interrupt for the body, we again read it as though it's a new message header, and also abandon it for the same reason (wrong size etc.) This essentially breaks things, and if that message was one that required a response, it leads to a deadlock as the device is waiting for the response but we'll never reply. Fix this by spinning on -EAGAIN as well when we read the message body. We need to handle -EAGAIN as "no message" while reading the header, since we share an interrupt. Note that this situation is highly unlikely to occur in normal usage, since there will be very few messages and only in the startup phase. With the inband call feature this does tend to happen (eventually) though. Signed-off-by: Johannes Berg <[email protected]> Signed-off-by: Richard Weinberger <[email protected]>
1 parent 04e5b1f commit 7e60746

File tree

1 file changed

+4
-4
lines changed

1 file changed

+4
-4
lines changed

arch/um/drivers/virtio_uml.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ static int full_sendmsg_fds(int fd, const void *buf, unsigned int len,
9191
return 0;
9292
}
9393

94-
static int full_read(int fd, void *buf, int len)
94+
static int full_read(int fd, void *buf, int len, bool abortable)
9595
{
9696
int rc;
9797

@@ -101,7 +101,7 @@ static int full_read(int fd, void *buf, int len)
101101
buf += rc;
102102
len -= rc;
103103
}
104-
} while (len && (rc > 0 || rc == -EINTR));
104+
} while (len && (rc > 0 || rc == -EINTR || (!abortable && rc == -EAGAIN)));
105105

106106
if (rc < 0)
107107
return rc;
@@ -112,7 +112,7 @@ static int full_read(int fd, void *buf, int len)
112112

113113
static int vhost_user_recv_header(int fd, struct vhost_user_msg *msg)
114114
{
115-
return full_read(fd, msg, sizeof(msg->header));
115+
return full_read(fd, msg, sizeof(msg->header), true);
116116
}
117117

118118
static int vhost_user_recv(struct virtio_uml_device *vu_dev,
@@ -135,7 +135,7 @@ static int vhost_user_recv(struct virtio_uml_device *vu_dev,
135135
size = msg->header.size;
136136
if (size > max_payload_size)
137137
return -EPROTO;
138-
return full_read(fd, &msg->payload, size);
138+
return full_read(fd, &msg->payload, size, false);
139139
}
140140

141141
static int vhost_user_recv_resp(struct virtio_uml_device *vu_dev,

0 commit comments

Comments
 (0)