[RFC 8/9] scsi: virtscsi: work around to abort a scmd

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch is just an "eg and test-issue" for this series. The main
changes is that when abort a scmd, distinguishing the case of removing
from the case of not found. ( I think it should be better to remove the
scmd directly from vq, but for the time being, I have no idea about
this detail in virtio)

Signed-off-by: Liu Ping Fan <pingfank@xxxxxxxxxxxxxxxxxx>
---
 drivers/scsi/virtio_scsi.c | 61 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 59 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index b26f1a5..d08aae5 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -31,8 +31,14 @@
 #define VIRTIO_SCSI_EVENT_LEN 8
 #define VIRTIO_SCSI_VQ_BASE 2
 
+/* should be per virtscsi dev */
+static struct list_head active_cmds = LIST_HEAD_INIT(active_cmds);
+static spinlock_t cmds_lock;
+
 /* Command queue element */
 struct virtio_scsi_cmd {
+	struct list_head list;
+	unsigned long abort;
 	struct scsi_cmnd *sc;
 	struct completion *comp;
 	union {
@@ -148,6 +154,18 @@ static void virtscsi_compute_resid(struct scsi_cmnd *sc, u32 resid)
 static void virtscsi_complete_cmd(struct virtio_scsi *vscsi, void *buf)
 {
 	struct virtio_scsi_cmd *cmd = buf;
+	unsigned long flags;
+	int skip = 0;
+	spin_lock_irqsave(&cmds_lock, flags);
+	list_del_init(&cmd->list);
+	if (cmd->abort)
+		skip = 1;
+	spin_unlock_irqrestore(&cmds_lock, flags);
+	if (skip) {
+		mempool_free(cmd, virtscsi_cmd_pool);
+		return;
+	}
+
 	struct scsi_cmnd *sc = cmd->sc;
 	struct virtio_scsi_cmd_resp *resp = &cmd->resp.cmd;
 	struct virtio_scsi_target_state *tgt =
@@ -273,11 +291,16 @@ static void virtscsi_req_done(struct virtqueue *vq)
 static void virtscsi_complete_free(struct virtio_scsi *vscsi, void *buf)
 {
 	struct virtio_scsi_cmd *cmd = buf;
+	unsigned long flags;
 
 	if (cmd->comp)
 		complete_all(cmd->comp);
-	else
+	else {
+		spin_lock_irqsave(&cmds_lock, flags);
+		list_del_init(&cmd->list);
+		spin_unlock_irqrestore(&cmds_lock, flags);
 		mempool_free(cmd, virtscsi_cmd_pool);
+	}
 }
 
 static void virtscsi_ctrl_done(struct virtqueue *vq)
@@ -477,6 +500,10 @@ static int virtscsi_kick_cmd(struct virtio_scsi_vq *vq,
 	int err;
 	bool needs_kick = false;
 
+	spin_lock_irqsave(&cmds_lock, flags);
+	list_add_tail(&cmd->list, &active_cmds);
+	spin_unlock_irqrestore(&cmds_lock, flags);
+
 	spin_lock_irqsave(&vq->vq_lock, flags);
 	err = virtscsi_add_cmd(vq->vq, cmd, req_size, resp_size, gfp);
 	if (!err)
@@ -495,6 +522,7 @@ static int virtscsi_queuecommand(struct virtio_scsi *vscsi,
 {
 	struct virtio_scsi_cmd *cmd;
 	int ret;
+	unsigned long flags;
 
 	struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev);
 	BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize);
@@ -511,6 +539,7 @@ static int virtscsi_queuecommand(struct virtio_scsi *vscsi,
 		goto out;
 
 	memset(cmd, 0, sizeof(*cmd));
+	INIT_LIST_HEAD(&cmd->list);
 	cmd->sc = sc;
 	cmd->req.cmd = (struct virtio_scsi_cmd_req){
 		.lun[0] = 1,
@@ -530,8 +559,12 @@ static int virtscsi_queuecommand(struct virtio_scsi *vscsi,
 			      sizeof cmd->req.cmd, sizeof cmd->resp.cmd,
 			      GFP_ATOMIC) == 0)
 		ret = 0;
-	else
+	else {
+		spin_lock_irqsave(&cmds_lock, flags);
+		list_del_init(&cmd->list);
+		spin_unlock_irqrestore(&cmds_lock, flags);
 		mempool_free(cmd, virtscsi_cmd_pool);
+	}
 
 out:
 	return ret;
@@ -590,6 +623,7 @@ static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
 {
 	DECLARE_COMPLETION_ONSTACK(comp);
 	int ret = FAILED;
+	unsigned long flags;
 
 	cmd->comp = &comp;
 	if (virtscsi_kick_cmd(&vscsi->ctrl_vq, cmd,
@@ -603,6 +637,9 @@ static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
 		ret = SUCCESS;
 
 out:
+	spin_lock_irqsave(&cmds_lock, flags);
+	list_del_init(&cmd->list);
+	spin_unlock_irqrestore(&cmds_lock, flags);
 	mempool_free(cmd, virtscsi_cmd_pool);
 	return ret;
 }
@@ -618,6 +655,7 @@ static int virtscsi_device_reset(struct scsi_cmnd *sc)
 		return FAILED;
 
 	memset(cmd, 0, sizeof(*cmd));
+	INIT_LIST_HEAD(&cmd->list);
 	cmd->sc = sc;
 	cmd->req.tmf = (struct virtio_scsi_ctrl_tmf_req){
 		.type = VIRTIO_SCSI_T_TMF,
@@ -634,13 +672,31 @@ static int virtscsi_abort(struct scsi_cmnd *sc)
 {
 	struct virtio_scsi *vscsi = shost_priv(sc->device->host);
 	struct virtio_scsi_cmd *cmd;
+	struct virtio_scsi_cmd *entry, *tmp;
+	unsigned long flags, found = 0;
 
 	scmd_printk(KERN_INFO, sc, "abort\n");
+	spin_lock_irqsave(&cmds_lock, flags);
+	list_for_each_entry_safe(entry, tmp, &active_cmds, list) {
+		if (entry->sc == sc) {
+			list_del_init(&entry->list);
+			/* mark the virtio_scsi_cmd as aborted
+			 */
+			entry->abort = 1;
+			found = 1;
+		}
+
+	}
+	spin_unlock_irqrestore(&cmds_lock, flags);
+	if (found)
+		return SUCCESS_REMOVE;
+
 	cmd = mempool_alloc(virtscsi_cmd_pool, GFP_NOIO);
 	if (!cmd)
 		return FAILED;
 
 	memset(cmd, 0, sizeof(*cmd));
+	INIT_LIST_HEAD(&cmd->list);
 	cmd->sc = sc;
 	cmd->req.tmf = (struct virtio_scsi_ctrl_tmf_req){
 		.type = VIRTIO_SCSI_T_TMF,
@@ -1030,6 +1086,7 @@ static int __init init(void)
 	if (ret < 0)
 		goto error;
 
+	spin_lock_init(&cmds_lock);
 	return 0;
 
 error:
-- 
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux