Skip to content

Commit af9fb41

Browse files
jmberg-intelrichardweinberger
authored andcommitted
um: virtio_uml: Fix broken device handling in time-travel
If a device implementation crashes, virtio_uml will mark it as dead by calling virtio_break_device() and scheduling the work that will remove it. This still seems like the right thing to do, but it's done directly while reading the message, and if time-travel is used, this is in the time-travel handler, outside of the normal Linux machinery. Therefore, we cannot acquire locks or do normal "linux-y" things because e.g. lockdep will be confused about the context. Move handling this situation out of the read function and into the actual IRQ handler and response handling instead, so that in the case of time-travel we don't call it in the wrong context. Chances are the system will still crash immediately, since the device implementation crashing may also cause the time- travel controller to go down, but at least all of that now happens without strange warnings from lockdep. Fixes: c8177ab ("um: time-travel: rework interrupt handling in ext mode") Cc: [email protected] Signed-off-by: Johannes Berg <[email protected]> Signed-off-by: Richard Weinberger <[email protected]>
1 parent d5a9597 commit af9fb41

File tree

1 file changed

+23
-10
lines changed

1 file changed

+23
-10
lines changed

arch/um/drivers/virtio_uml.c

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ struct virtio_uml_device {
6363

6464
u8 config_changed_irq:1;
6565
uint64_t vq_irq_vq_map;
66+
int recv_rc;
6667
};
6768

6869
struct virtio_uml_vq_info {
@@ -148,14 +149,6 @@ static int vhost_user_recv(struct virtio_uml_device *vu_dev,
148149

149150
rc = vhost_user_recv_header(fd, msg);
150151

151-
if (rc == -ECONNRESET && vu_dev->registered) {
152-
struct virtio_uml_platform_data *pdata;
153-
154-
pdata = vu_dev->pdata;
155-
156-
virtio_break_device(&vu_dev->vdev);
157-
schedule_work(&pdata->conn_broken_wk);
158-
}
159152
if (rc)
160153
return rc;
161154
size = msg->header.size;
@@ -164,15 +157,32 @@ static int vhost_user_recv(struct virtio_uml_device *vu_dev,
164157
return full_read(fd, &msg->payload, size, false);
165158
}
166159

160+
static void vhost_user_check_reset(struct virtio_uml_device *vu_dev,
161+
int rc)
162+
{
163+
struct virtio_uml_platform_data *pdata = vu_dev->pdata;
164+
165+
if (rc != -ECONNRESET)
166+
return;
167+
168+
if (!vu_dev->registered)
169+
return;
170+
171+
virtio_break_device(&vu_dev->vdev);
172+
schedule_work(&pdata->conn_broken_wk);
173+
}
174+
167175
static int vhost_user_recv_resp(struct virtio_uml_device *vu_dev,
168176
struct vhost_user_msg *msg,
169177
size_t max_payload_size)
170178
{
171179
int rc = vhost_user_recv(vu_dev, vu_dev->sock, msg,
172180
max_payload_size, true);
173181

174-
if (rc)
182+
if (rc) {
183+
vhost_user_check_reset(vu_dev, rc);
175184
return rc;
185+
}
176186

177187
if (msg->header.flags != (VHOST_USER_FLAG_REPLY | VHOST_USER_VERSION))
178188
return -EPROTO;
@@ -369,6 +379,7 @@ static irqreturn_t vu_req_read_message(struct virtio_uml_device *vu_dev,
369379
sizeof(msg.msg.payload) +
370380
sizeof(msg.extra_payload));
371381

382+
vu_dev->recv_rc = rc;
372383
if (rc)
373384
return IRQ_NONE;
374385

@@ -412,7 +423,9 @@ static irqreturn_t vu_req_interrupt(int irq, void *data)
412423
if (!um_irq_timetravel_handler_used())
413424
ret = vu_req_read_message(vu_dev, NULL);
414425

415-
if (vu_dev->vq_irq_vq_map) {
426+
if (vu_dev->recv_rc) {
427+
vhost_user_check_reset(vu_dev, vu_dev->recv_rc);
428+
} else if (vu_dev->vq_irq_vq_map) {
416429
struct virtqueue *vq;
417430

418431
virtio_device_for_each_vq((&vu_dev->vdev), vq) {

0 commit comments

Comments
 (0)