Skip to content

Commit 714e763

Browse files
BenjaminBeichlerrichardweinberger
authored andcommitted
um: read multiple msg from virtio slave request fd
If VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS is activated, the user mode linux virtio irq handler only read one msg from the corresponding socket. This creates issues, when the device emulation creates multiple call requests (e.g. for multiple virtqueues), as the socket buffer tend to fill up and the call requests are delayed. This creates a deadlock situation, when the device simulation blocks, because of sending a msg and the kernel side blocks because of synchronously waiting for an acknowledge of kick request. Actually inband notifications are meant to be used in combination with the time travel protocol, but it is not required, therefore this corner case needs to be handled. Anyways, in general it seems to be more natural to consume always all messages from a socket, instead of only a single one. Fixes: 2cd097b ("um: virtio: Implement VHOST_USER_PROTOCOL_F_SLAVE_REQ") Signed-off-by: Benjamin Beichler <[email protected]> Reviewed-by: Johannes Berg <[email protected]> Signed-off-by: Richard Weinberger <[email protected]>
1 parent 521a547 commit 714e763

File tree

1 file changed

+37
-34
lines changed

1 file changed

+37
-34
lines changed

arch/um/drivers/virtio_uml.c

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -374,45 +374,48 @@ static irqreturn_t vu_req_read_message(struct virtio_uml_device *vu_dev,
374374
u8 extra_payload[512];
375375
} msg;
376376
int rc;
377+
irqreturn_t irq_rc = IRQ_NONE;
377378

378-
rc = vhost_user_recv_req(vu_dev, &msg.msg,
379-
sizeof(msg.msg.payload) +
380-
sizeof(msg.extra_payload));
381-
382-
vu_dev->recv_rc = rc;
383-
if (rc)
384-
return IRQ_NONE;
385-
386-
switch (msg.msg.header.request) {
387-
case VHOST_USER_SLAVE_CONFIG_CHANGE_MSG:
388-
vu_dev->config_changed_irq = true;
389-
response = 0;
390-
break;
391-
case VHOST_USER_SLAVE_VRING_CALL:
392-
virtio_device_for_each_vq((&vu_dev->vdev), vq) {
393-
if (vq->index == msg.msg.payload.vring_state.index) {
394-
response = 0;
395-
vu_dev->vq_irq_vq_map |= BIT_ULL(vq->index);
396-
break;
379+
while (1) {
380+
rc = vhost_user_recv_req(vu_dev, &msg.msg,
381+
sizeof(msg.msg.payload) +
382+
sizeof(msg.extra_payload));
383+
if (rc)
384+
break;
385+
386+
switch (msg.msg.header.request) {
387+
case VHOST_USER_SLAVE_CONFIG_CHANGE_MSG:
388+
vu_dev->config_changed_irq = true;
389+
response = 0;
390+
break;
391+
case VHOST_USER_SLAVE_VRING_CALL:
392+
virtio_device_for_each_vq((&vu_dev->vdev), vq) {
393+
if (vq->index == msg.msg.payload.vring_state.index) {
394+
response = 0;
395+
vu_dev->vq_irq_vq_map |= BIT_ULL(vq->index);
396+
break;
397+
}
397398
}
399+
break;
400+
case VHOST_USER_SLAVE_IOTLB_MSG:
401+
/* not supported - VIRTIO_F_ACCESS_PLATFORM */
402+
case VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG:
403+
/* not supported - VHOST_USER_PROTOCOL_F_HOST_NOTIFIER */
404+
default:
405+
vu_err(vu_dev, "unexpected slave request %d\n",
406+
msg.msg.header.request);
398407
}
399-
break;
400-
case VHOST_USER_SLAVE_IOTLB_MSG:
401-
/* not supported - VIRTIO_F_ACCESS_PLATFORM */
402-
case VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG:
403-
/* not supported - VHOST_USER_PROTOCOL_F_HOST_NOTIFIER */
404-
default:
405-
vu_err(vu_dev, "unexpected slave request %d\n",
406-
msg.msg.header.request);
407-
}
408-
409-
if (ev && !vu_dev->suspended)
410-
time_travel_add_irq_event(ev);
411408

412-
if (msg.msg.header.flags & VHOST_USER_FLAG_NEED_REPLY)
413-
vhost_user_reply(vu_dev, &msg.msg, response);
409+
if (ev && !vu_dev->suspended)
410+
time_travel_add_irq_event(ev);
414411

415-
return IRQ_HANDLED;
412+
if (msg.msg.header.flags & VHOST_USER_FLAG_NEED_REPLY)
413+
vhost_user_reply(vu_dev, &msg.msg, response);
414+
irq_rc = IRQ_HANDLED;
415+
};
416+
/* mask EAGAIN as we try non-blocking read until socket is empty */
417+
vu_dev->recv_rc = (rc == -EAGAIN) ? 0 : rc;
418+
return irq_rc;
416419
}
417420

418421
static irqreturn_t vu_req_interrupt(int irq, void *data)

0 commit comments

Comments
 (0)