[PATCH 2/2] tcm_qla2xxx: Run ->check_stop_free and ->release_cmd with hardware_lock held

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

 



From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx>

This patch converts tcm_qla2xxx_release_cmd() + tcm_qla2xxx_check_stop_free() to
obtain qla_hw_data->hardware_lock when checking for qla_tgt_cmd related shutdown
bits.  This forces sychronization with qla_target.c:qla_tgt_wait_for_cmds()
code for the main release path in tcm_qla2xxx_release_cmd(), and also with
tcm_qla2xxx_check_stop_free() to determine if tcm_qla2xxx_release_cmd()
is waiting for the TFO->check_stop_free() to complete on ->cmd_stop_free_comp

It also removes the qla_tgt->tgt_stop and qla_tgt_sess->tearing_down checks
in tcm_qla2xxx_free_cmd(), and will always queue up outstanding descriptors
through the main tcm_qla2xxx_release_cmd() path in process context.  This
prevents an race where tcm_qla2xxx_free_cmd() was completing ->cmd_free_comp
to qla_tgt_wait_for_cmds() before TFO->check_stop_free() finished processing.

Reported-by: Roland Dreier <roland@xxxxxxxxxxxxxxx>
Cc: Roland Dreier <roland@xxxxxxxxxxxxxxx>
Cc: Madhuranath Iyengar <mni@xxxxxxxxxxxxxxxxxxxxx>
Signed-off-by: Nicholas Bellinger <nab@xxxxxxxxxxxxxxxxxxxxx>
---
 drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c |   68 +++++++++++++----------
 1 files changed, 39 insertions(+), 29 deletions(-)

diff --git a/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c
index 37f0b03..2660a57 100644
--- a/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c
+++ b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c
@@ -385,7 +385,7 @@ u32 tcm_qla2xxx_tpg_get_inst_index(struct se_portal_group *se_tpg)
 /*
  * Called from qla_target_template->free_cmd(), and will call
  * tcm_qla2xxx_release_cmd via normal struct target_core_fabric_ops
- * release callback.
+ * release callback.  qla_hw_data->hardware_lock is expected to be held
  */
 void tcm_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd)
 {
@@ -403,20 +403,6 @@ void tcm_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd)
 		return;
 	}
 
-	if (cmd->tgt->tgt_stop) {
-		pr_warn("tcm_qla2xxx_free_cmd: Detected tgt_stop"
-			" for cmd: %p !!!!!!\n", cmd);
-		complete(&cmd->cmd_free_comp);
-		return;
-	}
-
-	if (cmd->sess->tearing_down) {
-		pr_warn("tcm_qla2xxx_free_cmd: Detected tearing_down"
-			" for cmd: %p !!!!!!\n", cmd);
-		complete(&cmd->cmd_free_comp);
-		return;
-	}
-
 	if (!atomic_read(&cmd->se_cmd.t_transport_complete)) {
 		atomic_set(&cmd->cmd_stop_free, 1);
 		smp_mb__after_atomic_dec();
@@ -435,6 +421,8 @@ void tcm_qla2xxx_check_stop_free(struct se_cmd *se_cmd)
 {
 	struct qla_tgt_cmd *cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd);
 	struct qla_tgt_mgmt_cmd *mcmd;
+	struct qla_hw_data *ha;
+	unsigned long flags;
 
 	if (se_cmd->se_tmr_req) {
 		mcmd = container_of(se_cmd, struct qla_tgt_mgmt_cmd, se_cmd);
@@ -446,9 +434,16 @@ void tcm_qla2xxx_check_stop_free(struct se_cmd *se_cmd)
 		qla_tgt_free_mcmd(mcmd);
 		return;
 	}
-
+	ha = cmd->sess->vha->hw;
+	/*
+ 	 * Set cmd_stop_free and wakeup cmd_stop_free_comp if necessary
+ 	 * if tcm_qla2xxx_release_cmd() context is waiting for completion.
+ 	 */
+	spin_lock_irqsave(&ha->hardware_lock, flags);
 	atomic_set(&cmd->cmd_stop_free, 1);
-	barrier();
+	if (atomic_read(&cmd->cmd_free) != 0)
+		complete(&cmd->cmd_stop_free_comp);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
 /*
@@ -458,7 +453,8 @@ void tcm_qla2xxx_release_cmd(struct se_cmd *se_cmd)
 {
 	struct qla_tgt_cmd *cmd;
 	struct qla_tgt_sess *sess;
-	unsigned long flags;
+	struct qla_hw_data *ha;
+	unsigned long flags, flags2;
 
 	if (se_cmd->se_tmr_req != NULL)
 		return;
@@ -469,27 +465,41 @@ void tcm_qla2xxx_release_cmd(struct se_cmd *se_cmd)
 	if (!sess)
 		BUG();
 
-	while (atomic_read(&cmd->cmd_stop_free) != 1) {
-		pr_warn("Hit atomic_read(&cmd->cmd_stop_free)=1"
-				" in tcm_qla2xxx_release_cmd\n");
-		cpu_relax();
+	ha = sess->vha->hw;
+	/*
+	 * If the callback to tcm_qla2xxx_check_stop_free() has not finished,
+	 * before the release path is invoked, go ahead and wait on
+	 * cmd_stop_free_comp until tcm_qla2xxx_check_stop_free completes.
+	 */
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	if ((atomic_read(&cmd->cmd_stop_free) != 1) &&
+	    (atomic_read(&cmd->cmd_free_comp_set) == 0)) {
+		pr_warn("Detected cmd->cmd_stop_free != 0, waiting on"
+			" cmd_stop_free_comp for cmd: %p\n", cmd);
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		wait_for_completion(&cmd->cmd_stop_free_comp);
+		spin_lock_irqsave(&ha->hardware_lock, flags);
 	}
-
-
-	spin_lock_irqsave(&sess->sess_cmd_lock, flags);
+	/*
+	 * During shutdown, qla_tgt_wait_for_cmds() will be waiting on
+	 * this outstanding qla_tgt_cmd descriptor.  For this case,
+	 * perform the completion and return, and qla_tgt_wait_for_cmds()
+	 * will handle the direct call to qla_tgt_free_cmd()
+	 */
 	if (cmd->tgt->tgt_stop || sess->tearing_down) {
 		if (atomic_read(&cmd->cmd_free_comp_set) ||
 		    atomic_read(&cmd->cmd_free)) {
 			pr_warn("Detected shutdown, calling complete("
 				"&cmd->cmd_free_comp): cmd: %p\n", cmd);
-			spin_unlock_irqrestore(&sess->sess_cmd_lock, flags);
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
 			complete(&cmd->cmd_free_comp);
 			return;
 		}
 	}
-	if (atomic_read(&cmd->cmd_free))
-		list_del(&cmd->cmd_list);
-	spin_unlock_irqrestore(&sess->sess_cmd_lock, flags);
+	spin_lock_irqsave(&sess->sess_cmd_lock, flags2);
+	list_del(&cmd->cmd_list);
+	spin_unlock_irqrestore(&sess->sess_cmd_lock, flags2);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	qla_tgt_free_cmd(cmd);
 }
-- 
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