Skip to content

Commit 661e32f

Browse files
gkurzmstsirkin
authored andcommitted
virtio-scsi: convert virtio_scsi_bad_req() to use virtio_error()
The virtio_scsi_bad_req() function is called when a guest sends a request with missing or ill-sized headers. This generally happens when the virtio_scsi_parse_req() function returns an error. With this patch, virtio_scsi_bad_req() will mark the device as broken, detach the request from the virtqueue and free it, instead of forcing QEMU to exit. In nearly all locations where virtio_scsi_bad_req() is called, the only thing to do next is to return to the caller. The virtio_scsi_handle_cmd_req_prepare() function is an exception though. It is called in a loop by virtio_scsi_handle_cmd_vq() and passed requests freshly popped from a cmd virtqueue; virtio_scsi_handle_cmd_req_prepare() does some sanity checks on the request and returns a boolean flag to indicate whether the request should be queued or not. In the latter case, virtio_scsi_handle_cmd_req_prepare() has detected a non-fatal error and sent a response back to the guest. We have now a new condition to take into account: the device is broken and should stop all processing. The return value of virtio_scsi_handle_cmd_req_prepare() is hence changed to an int. A return value of zero means that the request should be queued. Other non-fatal error cases where the request shoudn't be queued return a negative errno (values are vaguely inspired by the error condition, but the only goal here is to discriminate the case we're interested in). And finally, if virtio_scsi_bad_req() was called, -EINVAL is returned. In this case, virtio_scsi_handle_cmd_vq() detaches and frees already queued requests, instead of submitting them. Signed-off-by: Greg Kurz <[email protected]> Reviewed-by: Stefan Hajnoczi <[email protected]> Reviewed-by: Michael S. Tsirkin <[email protected]> Signed-off-by: Michael S. Tsirkin <[email protected]>
1 parent fa5e56c commit 661e32f

File tree

1 file changed

+32
-14
lines changed

1 file changed

+32
-14
lines changed

hw/scsi/virtio-scsi.c

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,11 @@ static void virtio_scsi_complete_req(VirtIOSCSIReq *req)
8181
virtio_scsi_free_req(req);
8282
}
8383

84-
static void virtio_scsi_bad_req(void)
84+
static void virtio_scsi_bad_req(VirtIOSCSIReq *req)
8585
{
86-
error_report("wrong size for virtio-scsi headers");
87-
exit(1);
86+
virtio_error(VIRTIO_DEVICE(req->dev), "wrong size for virtio-scsi headers");
87+
virtqueue_detach_element(req->vq, &req->elem, 0);
88+
virtio_scsi_free_req(req);
8889
}
8990

9091
static size_t qemu_sgl_concat(VirtIOSCSIReq *req, struct iovec *iov,
@@ -387,15 +388,16 @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req)
387388

388389
if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0,
389390
&type, sizeof(type)) < sizeof(type)) {
390-
virtio_scsi_bad_req();
391+
virtio_scsi_bad_req(req);
391392
return;
392393
}
393394

394395
virtio_tswap32s(vdev, &type);
395396
if (type == VIRTIO_SCSI_T_TMF) {
396397
if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq),
397398
sizeof(VirtIOSCSICtrlTMFResp)) < 0) {
398-
virtio_scsi_bad_req();
399+
virtio_scsi_bad_req(req);
400+
return;
399401
} else {
400402
r = virtio_scsi_do_tmf(s, req);
401403
}
@@ -404,7 +406,8 @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req)
404406
type == VIRTIO_SCSI_T_AN_SUBSCRIBE) {
405407
if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlANReq),
406408
sizeof(VirtIOSCSICtrlANResp)) < 0) {
407-
virtio_scsi_bad_req();
409+
virtio_scsi_bad_req(req);
410+
return;
408411
} else {
409412
req->resp.an.event_actual = 0;
410413
req->resp.an.response = VIRTIO_SCSI_S_OK;
@@ -521,7 +524,7 @@ static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req)
521524
virtio_scsi_complete_cmd_req(req);
522525
}
523526

524-
static bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req)
527+
static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req)
525528
{
526529
VirtIOSCSICommon *vs = &s->parent_obj;
527530
SCSIDevice *d;
@@ -532,17 +535,18 @@ static bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req
532535
if (rc < 0) {
533536
if (rc == -ENOTSUP) {
534537
virtio_scsi_fail_cmd_req(req);
538+
return -ENOTSUP;
535539
} else {
536-
virtio_scsi_bad_req();
540+
virtio_scsi_bad_req(req);
541+
return -EINVAL;
537542
}
538-
return false;
539543
}
540544

541545
d = virtio_scsi_device_find(s, req->req.cmd.lun);
542546
if (!d) {
543547
req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET;
544548
virtio_scsi_complete_cmd_req(req);
545-
return false;
549+
return -ENOENT;
546550
}
547551
virtio_scsi_ctx_check(s, d);
548552
req->sreq = scsi_req_new(d, req->req.cmd.tag,
@@ -554,11 +558,11 @@ static bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req
554558
req->sreq->cmd.xfer > req->qsgl.size)) {
555559
req->resp.cmd.response = VIRTIO_SCSI_S_OVERRUN;
556560
virtio_scsi_complete_cmd_req(req);
557-
return false;
561+
return -ENOBUFS;
558562
}
559563
scsi_req_ref(req->sreq);
560564
blk_io_plug(d->conf.blk);
561-
return true;
565+
return 0;
562566
}
563567

564568
static void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req)
@@ -574,11 +578,24 @@ static void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req)
574578
void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
575579
{
576580
VirtIOSCSIReq *req, *next;
581+
int ret;
582+
577583
QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs);
578584

579585
while ((req = virtio_scsi_pop_req(s, vq))) {
580-
if (virtio_scsi_handle_cmd_req_prepare(s, req)) {
586+
ret = virtio_scsi_handle_cmd_req_prepare(s, req);
587+
if (!ret) {
581588
QTAILQ_INSERT_TAIL(&reqs, req, next);
589+
} else if (ret == -EINVAL) {
590+
/* The device is broken and shouldn't process any request */
591+
while (!QTAILQ_EMPTY(&reqs)) {
592+
req = QTAILQ_FIRST(&reqs);
593+
QTAILQ_REMOVE(&reqs, req, next);
594+
blk_io_unplug(req->sreq->dev->conf.blk);
595+
scsi_req_unref(req->sreq);
596+
virtqueue_detach_element(req->vq, &req->elem, 0);
597+
virtio_scsi_free_req(req);
598+
}
582599
}
583600
}
584601

@@ -708,7 +725,8 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
708725
}
709726

710727
if (virtio_scsi_parse_req(req, 0, sizeof(VirtIOSCSIEvent))) {
711-
virtio_scsi_bad_req();
728+
virtio_scsi_bad_req(req);
729+
goto out;
712730
}
713731

714732
evt = &req->resp.event;

0 commit comments

Comments
 (0)