mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
scsi: virtio_scsi: implement request batching
Adding the command and kicking the virtqueue so far was done one after another. Make the kick optional, so that we can take into account SCMD_LAST. We also need a commit_rqs callback to kick the device if blk-mq aborts the submission before the last request is reached. Suggested-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Hannes Reinecke <hare@suse.com> Reviewed-by: Ming Lei <ming.lei@redhat.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
8930a6c207
commit
9e5470fe2d
@ -369,14 +369,7 @@ static void virtscsi_event_done(struct virtqueue *vq)
|
||||
virtscsi_vq_done(vscsi, &vscsi->event_vq, virtscsi_complete_event);
|
||||
};
|
||||
|
||||
/**
|
||||
* virtscsi_add_cmd - add a virtio_scsi_cmd to a virtqueue
|
||||
* @vq : the struct virtqueue we're talking about
|
||||
* @cmd : command structure
|
||||
* @req_size : size of the request buffer
|
||||
* @resp_size : size of the response buffer
|
||||
*/
|
||||
static int virtscsi_add_cmd(struct virtqueue *vq,
|
||||
static int __virtscsi_add_cmd(struct virtqueue *vq,
|
||||
struct virtio_scsi_cmd *cmd,
|
||||
size_t req_size, size_t resp_size)
|
||||
{
|
||||
@ -421,17 +414,39 @@ static int virtscsi_add_cmd(struct virtqueue *vq,
|
||||
return virtqueue_add_sgs(vq, sgs, out_num, in_num, cmd, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
static int virtscsi_kick_cmd(struct virtio_scsi_vq *vq,
|
||||
static void virtscsi_kick_vq(struct virtio_scsi_vq *vq)
|
||||
{
|
||||
bool needs_kick;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&vq->vq_lock, flags);
|
||||
needs_kick = virtqueue_kick_prepare(vq->vq);
|
||||
spin_unlock_irqrestore(&vq->vq_lock, flags);
|
||||
|
||||
if (needs_kick)
|
||||
virtqueue_notify(vq->vq);
|
||||
}
|
||||
|
||||
/**
|
||||
* virtscsi_add_cmd - add a virtio_scsi_cmd to a virtqueue, optionally kick it
|
||||
* @vq : the struct virtqueue we're talking about
|
||||
* @cmd : command structure
|
||||
* @req_size : size of the request buffer
|
||||
* @resp_size : size of the response buffer
|
||||
* @kick : whether to kick the virtqueue immediately
|
||||
*/
|
||||
static int virtscsi_add_cmd(struct virtio_scsi_vq *vq,
|
||||
struct virtio_scsi_cmd *cmd,
|
||||
size_t req_size, size_t resp_size)
|
||||
size_t req_size, size_t resp_size,
|
||||
bool kick)
|
||||
{
|
||||
unsigned long flags;
|
||||
int err;
|
||||
bool needs_kick = false;
|
||||
|
||||
spin_lock_irqsave(&vq->vq_lock, flags);
|
||||
err = virtscsi_add_cmd(vq->vq, cmd, req_size, resp_size);
|
||||
if (!err)
|
||||
err = __virtscsi_add_cmd(vq->vq, cmd, req_size, resp_size);
|
||||
if (!err && kick)
|
||||
needs_kick = virtqueue_kick_prepare(vq->vq);
|
||||
|
||||
spin_unlock_irqrestore(&vq->vq_lock, flags);
|
||||
@ -496,6 +511,7 @@ static int virtscsi_queuecommand(struct Scsi_Host *shost,
|
||||
struct virtio_scsi *vscsi = shost_priv(shost);
|
||||
struct virtio_scsi_vq *req_vq = virtscsi_pick_vq_mq(vscsi, sc);
|
||||
struct virtio_scsi_cmd *cmd = scsi_cmd_priv(sc);
|
||||
bool kick;
|
||||
unsigned long flags;
|
||||
int req_size;
|
||||
int ret;
|
||||
@ -525,7 +541,8 @@ static int virtscsi_queuecommand(struct Scsi_Host *shost,
|
||||
req_size = sizeof(cmd->req.cmd);
|
||||
}
|
||||
|
||||
ret = virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd));
|
||||
kick = (sc->flags & SCMD_LAST) != 0;
|
||||
ret = virtscsi_add_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd), kick);
|
||||
if (ret == -EIO) {
|
||||
cmd->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET;
|
||||
spin_lock_irqsave(&req_vq->vq_lock, flags);
|
||||
@ -543,8 +560,8 @@ static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
|
||||
int ret = FAILED;
|
||||
|
||||
cmd->comp = ∁
|
||||
if (virtscsi_kick_cmd(&vscsi->ctrl_vq, cmd,
|
||||
sizeof cmd->req.tmf, sizeof cmd->resp.tmf) < 0)
|
||||
if (virtscsi_add_cmd(&vscsi->ctrl_vq, cmd,
|
||||
sizeof cmd->req.tmf, sizeof cmd->resp.tmf, true) < 0)
|
||||
goto out;
|
||||
|
||||
wait_for_completion(&comp);
|
||||
@ -658,6 +675,13 @@ static int virtscsi_map_queues(struct Scsi_Host *shost)
|
||||
return blk_mq_virtio_map_queues(qmap, vscsi->vdev, 2);
|
||||
}
|
||||
|
||||
static void virtscsi_commit_rqs(struct Scsi_Host *shost, u16 hwq)
|
||||
{
|
||||
struct virtio_scsi *vscsi = shost_priv(shost);
|
||||
|
||||
virtscsi_kick_vq(&vscsi->req_vqs[hwq]);
|
||||
}
|
||||
|
||||
/*
|
||||
* The host guarantees to respond to each command, although I/O
|
||||
* latencies might be higher than on bare metal. Reset the timer
|
||||
@ -675,6 +699,7 @@ static struct scsi_host_template virtscsi_host_template = {
|
||||
.this_id = -1,
|
||||
.cmd_size = sizeof(struct virtio_scsi_cmd),
|
||||
.queuecommand = virtscsi_queuecommand,
|
||||
.commit_rqs = virtscsi_commit_rqs,
|
||||
.change_queue_depth = virtscsi_change_queue_depth,
|
||||
.eh_abort_handler = virtscsi_abort,
|
||||
.eh_device_reset_handler = virtscsi_device_reset,
|
||||
|
Loading…
Reference in New Issue
Block a user