From c52ea801cbf5c356a0b9e7b0f667280a5845d122 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: <67fe78a504035b7baf527bbd4726c75b0a1f8ba4.1429847625.git.jen@redhat.com> References: <67fe78a504035b7baf527bbd4726c75b0a1f8ba4.1429847625.git.jen@redhat.com> From: Fam Zheng Date: Wed, 22 Apr 2015 03:17:55 -0500 Subject: [CHANGE 6/7] virtio-blk: Use blk_aio_ioctl To: rhvirt-patches@redhat.com, jen@redhat.com RH-Author: Fam Zheng Message-id: <1429672676-18444-5-git-send-email-famz@redhat.com> Patchwork-id: 64864 O-Subject: [RHEL-6.7 qemu-kvm PATCH v4 4/5] virtio-blk: Use blk_aio_ioctl Bugzilla: 1006871 RH-Acked-by: Paolo Bonzini RH-Acked-by: Kevin Wolf RH-Acked-by: Juan Quintela Use the asynchronous interface of ioctl. This will not make the VM unresponsive if the ioctl takes a long time. Signed-off-by: Fam Zheng Reviewed-by: Paolo Bonzini Signed-off-by: Kevin Wolf (cherry picked from commit 1dc936aa84b300940b2797c391cc3ca519bc78ce) Signed-off-by: Fam Zheng Signed-off-by: Jeff E. Nelson Conflicts: hw/block/virtio-blk.c Apply to hw/virtio-blk.c, with below differences: blk_aio_ioctl -> bdrv_aio_ioctl virtio_blk_free_request -> qemu_free --- hw/virtio-blk.c | 125 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 75 insertions(+), 50 deletions(-) Signed-off-by: Jeff E. Nelson --- hw/virtio-blk.c | 125 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 75 insertions(+), 50 deletions(-) diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 1f394dd..fd2705a 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -137,6 +137,51 @@ static VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s) return req; } +#ifdef __linux__ + +typedef struct { + VirtIOBlockReq *req; + struct sg_io_hdr hdr; +} VirtIOBlockIoctlReq; + +static void virtio_blk_ioctl_complete(void *opaque, int status) +{ + VirtIOBlockIoctlReq *ioctl_req = opaque; + VirtIOBlockReq *req = ioctl_req->req; + struct sg_io_hdr *hdr; + + if (status) { + status = VIRTIO_BLK_S_UNSUPP; + req->scsi->errors = 255; + goto out; + } + + hdr = &ioctl_req->hdr; + /* + * From SCSI-Generic-HOWTO: "Some lower level drivers (e.g. ide-scsi) + * clear the masked_status field [hence status gets cleared too, see + * block/scsi_ioctl.c] even when a CHECK_CONDITION or COMMAND_TERMINATED + * status has occurred. However they do set DRIVER_SENSE in driver_status + * field. Also a (sb_len_wr > 0) indicates there is a sense buffer. + */ + if (hdr->status == 0 && hdr->sb_len_wr > 0) { + hdr->status = CHECK_CONDITION; + } + + req->scsi->errors = hdr->status | (hdr->msg_status << 8) | + (hdr->host_status << 16) | (hdr->driver_status << 24); + req->scsi->residual = hdr->resid; + req->scsi->sense_len = hdr->sb_len_wr; + req->scsi->data_len = hdr->dxfer_len; + +out: + virtio_blk_req_complete(req, status); + qemu_free(req); + g_free(ioctl_req); +} + +#endif + static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s) { VirtIOBlockReq *req = virtio_blk_alloc_request(s); @@ -153,9 +198,12 @@ static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s) static void virtio_blk_handle_scsi(VirtIOBlockReq *req) { - int ret; +#ifdef __linux__ int status = VIRTIO_BLK_S_OK; int i; + VirtIOBlockIoctlReq *ioctl_req; + VirtQueueElement *elem = &req->elem; + /* * We require at least one output segment each for the virtio_blk_outhdr @@ -189,83 +237,60 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) goto fail; } -#ifdef __linux__ - struct sg_io_hdr hdr; - memset(&hdr, 0, sizeof(struct sg_io_hdr)); - hdr.interface_id = 'S'; - hdr.cmd_len = req->elem.out_sg[1].iov_len; - hdr.cmdp = req->elem.out_sg[1].iov_base; - hdr.dxfer_len = 0; + ioctl_req = g_new0(VirtIOBlockIoctlReq, 1); + ioctl_req->req = req; + ioctl_req->hdr.interface_id = 'S'; + ioctl_req->hdr.cmd_len = elem->out_sg[1].iov_len; + ioctl_req->hdr.cmdp = elem->out_sg[1].iov_base; + ioctl_req->hdr.dxfer_len = 0; if (req->elem.out_num > 2) { /* * If there are more than the minimally required 2 output segments * there is write payload starting from the third iovec. */ - hdr.dxfer_direction = SG_DXFER_TO_DEV; - hdr.iovec_count = req->elem.out_num - 2; + ioctl_req->hdr.dxfer_direction = SG_DXFER_TO_DEV; + ioctl_req->hdr.iovec_count = elem->out_num - 2; - for (i = 0; i < hdr.iovec_count; i++) - hdr.dxfer_len += req->elem.out_sg[i + 2].iov_len; + for (i = 0; i < ioctl_req->hdr.iovec_count; i++) { + ioctl_req->hdr.dxfer_len += elem->out_sg[i + 2].iov_len; + } - hdr.dxferp = req->elem.out_sg + 2; + ioctl_req->hdr.dxferp = elem->out_sg + 2; } else if (req->elem.in_num > 3) { /* * If we have more than 3 input segments the guest wants to actually * read data. */ - hdr.dxfer_direction = SG_DXFER_FROM_DEV; - hdr.iovec_count = req->elem.in_num - 3; - for (i = 0; i < hdr.iovec_count; i++) - hdr.dxfer_len += req->elem.in_sg[i].iov_len; + ioctl_req->hdr.dxfer_direction = SG_DXFER_FROM_DEV; + ioctl_req->hdr.iovec_count = elem->in_num - 3; + for (i = 0; i < ioctl_req->hdr.iovec_count; i++) { + ioctl_req->hdr.dxfer_len += elem->in_sg[i].iov_len; + } - hdr.dxferp = req->elem.in_sg; + ioctl_req->hdr.dxferp = elem->in_sg; } else { /* * Some SCSI commands don't actually transfer any data. */ - hdr.dxfer_direction = SG_DXFER_NONE; + ioctl_req->hdr.dxfer_direction = SG_DXFER_NONE; } - hdr.sbp = req->elem.in_sg[req->elem.in_num - 3].iov_base; - hdr.mx_sb_len = req->elem.in_sg[req->elem.in_num - 3].iov_len; + ioctl_req->hdr.sbp = elem->in_sg[elem->in_num - 3].iov_base; + ioctl_req->hdr.mx_sb_len = elem->in_sg[elem->in_num - 3].iov_len; - ret = bdrv_ioctl(req->dev->bs, SG_IO, &hdr); - if (ret) { - status = VIRTIO_BLK_S_UNSUPP; - goto fail; - } - - /* - * From SCSI-Generic-HOWTO: "Some lower level drivers (e.g. ide-scsi) - * clear the masked_status field [hence status gets cleared too, see - * block/scsi_ioctl.c] even when a CHECK_CONDITION or COMMAND_TERMINATED - * status has occurred. However they do set DRIVER_SENSE in driver_status - * field. Also a (sb_len_wr > 0) indicates there is a sense buffer. - */ - if (hdr.status == 0 && hdr.sb_len_wr > 0) { - hdr.status = CHECK_CONDITION; - } - - req->scsi->errors = hdr.status | (hdr.msg_status << 8) | - (hdr.host_status << 16) | (hdr.driver_status << 24); - req->scsi->residual = hdr.resid; - req->scsi->sense_len = hdr.sb_len_wr; - req->scsi->data_len = hdr.dxfer_len; - - virtio_blk_req_complete(req, status); - qemu_free(req); + bdrv_aio_ioctl(req->dev->bs, SG_IO, &ioctl_req->hdr, + virtio_blk_ioctl_complete, ioctl_req); return; -#else - abort(); -#endif - fail: /* Just put anything nonzero so that the ioctl fails in the guest. */ stl_p(&req->scsi->errors, 255); virtio_blk_req_complete(req, status); qemu_free(req); +#else + abort(); +#endif } static void do_multiwrite(BlockDriverState *bs, BlockRequest *blkreq, -- 2.1.0