[PATCH 1/2] qla2xxx: Run qla_tgt_wait_for_cmds state checks with hardware_lock held

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

 



From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx>

This patch converts qla_tgt_wait_for_cmds() to hold qla_hw_data->hardware_lock
for qla_tgt_cmd state checks related to shutdown logic.  This also includes
setting ->cmd_free_comp_set for all cases to signal shutdown in tcm_qla2xxx
code, and the removal of se_cmd->transport_wait_for_tasks() that forces all
outstanding descriptors to complete before tcm_qla2xxx code wakes up
->cmd_free_comp.

This patch also adds a secondary check in qla_tgt_handle_cmd_for_atio()
for qla_tgt->tgt_stop to prevent incoming I/O during full shutdown before
all qla_tgt_sess instances may have their ->tearing_down set, and adds
qla_tgt_cmd->cmd_stop_free_comp used by tcm_qla2xxx code to handle a
seperate completion race.

Reported-by: Roland Dreier <roland@xxxxxxxxxxxxxxx>
Cc: Roland Dreier <roland@xxxxxxxxxxxxxxx>
Cc: Madhuranath Iyengar <mni@xxxxxxxxxxxxxxxxxxxxx>
Signed-off-by: Nicholas Bellinger <nab@xxxxxxxxxxxxxxxxxxxxx>
---
 drivers/scsi/qla2xxx/qla_target.c |   52 +++++++++++++++---------------------
 drivers/scsi/qla2xxx/qla_target.h |    1 +
 2 files changed, 23 insertions(+), 30 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 757e971..66eedd6 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -369,13 +369,15 @@ void qla_tgt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt)
 
 }
 
-static void qla_tgt_wait_for_cmds(struct qla_tgt_sess *sess)
+/*
+ * Called with qla_hw_data->hardware_lock held.
+ */
+static void qla_tgt_wait_for_cmds(struct qla_tgt_sess *sess, struct qla_hw_data *ha)
 {
 	LIST_HEAD(tmp_list);
 	struct qla_tgt_cmd *cmd;
 	struct se_cmd *se_cmd;
 	unsigned long flags;
-	int cmd_free;
 
 	spin_lock_irqsave(&sess->sess_cmd_lock, flags);
 	list_splice_init(&sess->sess_cmd_list, &tmp_list);
@@ -386,38 +388,27 @@ static void qla_tgt_wait_for_cmds(struct qla_tgt_sess *sess)
 		cmd = list_entry(tmp_list.next, struct qla_tgt_cmd, cmd_list);
 		DEBUG22(qla_printk(KERN_INFO, sess->vha->hw, "Waiting for cmd:"
 			" %p\n", cmd));
+		/*
+		 * This will signal that completion should be called from
+		 * tcm_qla2xxx_release_cmd() context.
+		 */ 
+		atomic_set(&cmd->cmd_free_comp_set, 1);
+		spin_unlock_irq(&ha->hardware_lock);
 
-		if ((atomic_read(&cmd->cmd_free) != 0) ||
-		    (atomic_read(&cmd->cmd_stop_free) != 0))	
-			cmd_free = 1;
-		else {
-			cmd_free = 0;
-			atomic_set(&cmd->cmd_free_comp_set, 1);
-			smp_mb__after_atomic_dec();
-		}
 		list_del(&cmd->cmd_list);
 
-		DEBUG22(qla_printk(KERN_INFO, sess->vha->hw, "Waiting for cmd: %p,"
-				" cmd_free: %d\n", cmd, cmd_free));
-
 		se_cmd = &cmd->se_cmd;
-
-		if (!cmd_free) {
-			if (se_cmd->transport_wait_for_tasks) {
-				DEBUG22(qla_printk(KERN_INFO, sess->vha->hw, "Before"
-					" se_cmd->transport_wait_for_tasks cmd:"
-					" %p, se_cmd: %p\n", cmd, se_cmd));
-				se_cmd->transport_wait_for_tasks(se_cmd, 0, 0);
-
-				DEBUG22(qla_printk(KERN_INFO, sess->vha->hw, "After"
-					" se_cmd->transport_wait_for_tasks ----------->\n"));
-			}
-		}
-		
+		/*
+		 * Wait for completion of the outstanding descriptor in
+		 * tcm_qla2xxx_release_cmd() from transport processing
+		 * context, then a direct call to qla_tgt_free_cmd() below.
+		 */
 		DEBUG22(qla_printk(KERN_INFO, sess->vha->hw, "Before"
 			" wait_for_completion(&cmd->cmd_free_comp); cmd: %p,"
 			" se_cmd: %p\n", cmd, se_cmd));
+
 		wait_for_completion(&cmd->cmd_free_comp);
+
 		DEBUG22(qla_printk(KERN_INFO, sess->vha->hw, "After"
 			" wait_for_completion(&cmd->cmd_free_comp); cmd: %p,"
 			" se_cmd: %p\n", cmd, se_cmd));
@@ -429,6 +420,8 @@ static void qla_tgt_wait_for_cmds(struct qla_tgt_sess *sess)
 
 		DEBUG22(qla_printk(KERN_INFO, sess->vha->hw, "After"
 			" qla_tgt_free_cmd --------------------->\n"));
+
+		spin_lock_irq(&ha->hardware_lock);
 	}
 
 }
@@ -444,9 +437,7 @@ static void qla_tgt_free_session_done(struct qla_tgt_sess *sess)
 	tgt = sess->tgt;
 
 	sess->tearing_down = 1;
-	spin_unlock_irq(&ha->hardware_lock);
-	qla_tgt_wait_for_cmds(sess);
-	spin_lock_irq(&ha->hardware_lock);
+	qla_tgt_wait_for_cmds(sess, ha);
 
 	/*
 	 * Release the target session for FC Nexus from fabric module code.
@@ -3294,6 +3285,7 @@ static int qla_tgt_handle_cmd_for_atio(struct scsi_qla_host *vha, atio_t *atio)
 
 	INIT_LIST_HEAD(&cmd->cmd_list);
 	init_completion(&cmd->cmd_free_comp);
+	init_completion(&cmd->cmd_stop_free_comp);
 
 	memcpy(&cmd->atio.atio2x, atio, sizeof(*atio));
 	cmd->state = QLA_TGT_STATE_NEW;
@@ -3324,7 +3316,7 @@ static int qla_tgt_handle_cmd_for_atio(struct scsi_qla_host *vha, atio_t *atio)
 		}
 	}
 
-	if (sess->tearing_down)
+	if (sess->tearing_down || tgt->tgt_stop)
 		goto out_free_cmd;
 
 	res = qla_tgt_send_cmd_to_target(vha, cmd, sess);
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index 42d5479..0e5cbfd8 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -902,6 +902,7 @@ struct qla_tgt_cmd {
 	atomic_t cmd_free;
 	atomic_t cmd_free_comp_set;
 	struct completion cmd_free_comp;
+	struct completion cmd_stop_free_comp;
 	struct se_cmd se_cmd;
 	/* Sense buffer that will be mapped into outgoing status */
 	unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER];
-- 
1.7.2.5

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


[Index of Archives]     [Linux SCSI]     [Kernel Newbies]     [Linux SCSI Target Infrastructure]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Device Mapper]

  Powered by Linux