diff options
Diffstat (limited to 'drivers/vhost/scsi.c')
-rw-r--r-- | drivers/vhost/scsi.c | 53 |
1 files changed, 32 insertions, 21 deletions
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index f34f9895b8..006ffacf1c 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -210,6 +210,7 @@ struct vhost_scsi { struct vhost_scsi_tmf { struct vhost_work vwork; + struct work_struct flush_work; struct vhost_scsi *vhost; struct vhost_scsi_virtqueue *svq; @@ -358,14 +359,23 @@ static void vhost_scsi_release_tmf_res(struct vhost_scsi_tmf *tmf) vhost_scsi_put_inflight(inflight); } +static void vhost_scsi_drop_cmds(struct vhost_scsi_virtqueue *svq) +{ + struct vhost_scsi_cmd *cmd, *t; + struct llist_node *llnode; + + llnode = llist_del_all(&svq->completion_list); + llist_for_each_entry_safe(cmd, t, llnode, tvc_completion_list) + vhost_scsi_release_cmd_res(&cmd->tvc_se_cmd); +} + static void vhost_scsi_release_cmd(struct se_cmd *se_cmd) { if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) { struct vhost_scsi_tmf *tmf = container_of(se_cmd, struct vhost_scsi_tmf, se_cmd); - struct vhost_virtqueue *vq = &tmf->svq->vq; - vhost_vq_work_queue(vq, &tmf->vwork); + schedule_work(&tmf->flush_work); } else { struct vhost_scsi_cmd *cmd = container_of(se_cmd, struct vhost_scsi_cmd, tvc_se_cmd); @@ -373,7 +383,8 @@ static void vhost_scsi_release_cmd(struct se_cmd *se_cmd) struct vhost_scsi_virtqueue, vq); llist_add(&cmd->tvc_completion_list, &svq->completion_list); - vhost_vq_work_queue(&svq->vq, &svq->completion_work); + if (!vhost_vq_work_queue(&svq->vq, &svq->completion_work)) + vhost_scsi_drop_cmds(svq); } } @@ -1276,33 +1287,32 @@ static void vhost_scsi_tmf_resp_work(struct vhost_work *work) { struct vhost_scsi_tmf *tmf = container_of(work, struct vhost_scsi_tmf, vwork); - struct vhost_virtqueue *ctl_vq, *vq; - int resp_code, i; - - if (tmf->scsi_resp == TMR_FUNCTION_COMPLETE) { - /* - * Flush IO vqs that don't share a worker with the ctl to make - * sure they have sent their responses before us. - */ - ctl_vq = &tmf->vhost->vqs[VHOST_SCSI_VQ_CTL].vq; - for (i = VHOST_SCSI_VQ_IO; i < tmf->vhost->dev.nvqs; i++) { - vq = &tmf->vhost->vqs[i].vq; - - if (vhost_vq_is_setup(vq) && - vq->worker != ctl_vq->worker) - vhost_vq_flush(vq); - } + int resp_code; + if (tmf->scsi_resp == TMR_FUNCTION_COMPLETE) resp_code = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; - } else { + else resp_code = VIRTIO_SCSI_S_FUNCTION_REJECTED; - } vhost_scsi_send_tmf_resp(tmf->vhost, &tmf->svq->vq, tmf->in_iovs, tmf->vq_desc, &tmf->resp_iov, resp_code); vhost_scsi_release_tmf_res(tmf); } +static void vhost_scsi_tmf_flush_work(struct work_struct *work) +{ + struct vhost_scsi_tmf *tmf = container_of(work, struct vhost_scsi_tmf, + flush_work); + struct vhost_virtqueue *vq = &tmf->svq->vq; + /* + * Make sure we have sent responses for other commands before we + * send our response. + */ + vhost_dev_flush(vq->dev); + if (!vhost_vq_work_queue(vq, &tmf->vwork)) + vhost_scsi_release_tmf_res(tmf); +} + static void vhost_scsi_handle_tmf(struct vhost_scsi *vs, struct vhost_scsi_tpg *tpg, struct vhost_virtqueue *vq, @@ -1326,6 +1336,7 @@ vhost_scsi_handle_tmf(struct vhost_scsi *vs, struct vhost_scsi_tpg *tpg, if (!tmf) goto send_reject; + INIT_WORK(&tmf->flush_work, vhost_scsi_tmf_flush_work); vhost_work_init(&tmf->vwork, vhost_scsi_tmf_resp_work); tmf->vhost = vs; tmf->svq = svq; |