[PATCH v6 05/33] tcm_qla2xxx: Fix reference leaks related to aborting commands

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

 



Since it is almost impossible to verify that the current qla2xxx
target code calls transport_generic_free_cmd() after processing
of a command has finished, rework the target code as follows:
- Remove the code for freeing a command from
  qlt_send_term_exchange() and make the callers of this function
  responsible for freeing a command.
- Remove qlt_abort_cmd_on_host_reset(). Since that function freed
  the command it aborted, move the responsibility for freeing a
  command to the callers of that code.
- In all TCM callback functions, ensure that either an error
  code is returned, the hardware will trigger an interrupt later
  on or that 0 is returned and transport_generic_free_cmd() is
  called.

Signed-off-by: Bart Van Assche <bart.vanassche@xxxxxxxxxxx>
Cc: Himanshu Madhani <himanshu.madhani@xxxxxxxxxx>
Cc: Quinn Tran <quinn.tran@xxxxxxxxxx>
---
 drivers/scsi/qla2xxx/qla_target.c  | 66 +++++---------------------------------
 drivers/scsi/qla2xxx/tcm_qla2xxx.c | 33 +++++++++++++++----
 2 files changed, 35 insertions(+), 64 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 5a3fd2c63512..3ffa99a4daff 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -115,8 +115,6 @@ static int qlt_issue_task_mgmt(struct fc_port *sess, u64 lun,
 	int fn, void *iocb, int flags);
 static void qlt_send_term_exchange(struct scsi_qla_host *ha, struct qla_tgt_cmd
 	*cmd, struct atio_from_isp *atio, int ha_locked, int ul_abort);
-static void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha,
-	struct qla_tgt_cmd *cmd);
 static void qlt_alloc_qfull_cmd(struct scsi_qla_host *vha,
 	struct atio_from_isp *atio, uint16_t status, int qfull);
 static void qlt_disable_vha(struct scsi_qla_host *vha);
@@ -2860,13 +2858,10 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	if (cmd->sess && cmd->sess->deleted) {
 		cmd->state = QLA_TGT_STATE_PROCESSED;
-		if (cmd->sess->logout_completed)
-			/* no need to terminate. FW already freed exchange. */
-			qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
-		else
+		if (!cmd->sess->logout_completed)
 			qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
-		return 0;
+		return -ENOENT;
 	}
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
@@ -2897,13 +2892,12 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
 		 * previous life, just abort the processing.
 		 */
 		cmd->state = QLA_TGT_STATE_PROCESSED;
-		qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
 		ql_dbg(ql_dbg_async, vha, 0xe101,
 			"RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n",
 			vha->flags.online, qla2x00_reset_active(vha),
 			cmd->reset_count, ha->chip_reset);
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
-		return 0;
+		return -ENOENT;
 	}
 
 	/* Does F/W have an IOCBs for this request */
@@ -3039,13 +3033,12 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
 		 * previous life, just abort the processing.
 		 */
 		cmd->state = QLA_TGT_STATE_NEED_DATA;
-		qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
 		ql_dbg(ql_dbg_async, vha, 0xe102,
 			"RESET-XFR online/active/old-count/new-count = %d/%d/%d/%d.\n",
 			vha->flags.online, qla2x00_reset_active(vha),
 			cmd->reset_count, ha->chip_reset);
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
-		return 0;
+		return -EINTR;
 	}
 
 	/* Does F/W have an IOCBs for this request */
@@ -3395,12 +3388,6 @@ static void qlt_send_term_exchange(struct scsi_qla_host *vha,
 		qlt_alloc_qfull_cmd(vha, atio, 0, 0);
 
 done:
-	if (cmd && !ul_abort && !cmd->aborted) {
-		if (cmd->sg_mapped)
-			qlt_unmap_sg(vha, cmd);
-		vha->hw->tgt.tgt_ops->free_cmd(cmd);
-	}
-
 	if (!ha_locked)
 		spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
 
@@ -3596,42 +3583,6 @@ static struct qla_tgt_cmd *qlt_ctio_to_cmd(struct scsi_qla_host *vha,
 	return cmd;
 }
 
-/* hardware_lock should be held by caller. */
-static void
-qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd)
-{
-	struct qla_hw_data *ha = vha->hw;
-	uint32_t handle;
-
-	if (cmd->sg_mapped)
-		qlt_unmap_sg(vha, cmd);
-
-	handle = qlt_make_handle(vha);
-
-	/* TODO: fix debug message type and ids. */
-	if (cmd->state == QLA_TGT_STATE_PROCESSED) {
-		ql_dbg(ql_dbg_io, vha, 0xff00,
-		    "HOST-ABORT: handle=%d, state=PROCESSED.\n", handle);
-	} else if (cmd->state == QLA_TGT_STATE_NEED_DATA) {
-		cmd->write_data_transferred = 0;
-		cmd->state = QLA_TGT_STATE_DATA_IN;
-
-		ql_dbg(ql_dbg_io, vha, 0xff01,
-		    "HOST-ABORT: handle=%d, state=DATA_IN.\n", handle);
-
-		ha->tgt.tgt_ops->handle_data(cmd);
-		return;
-	} else {
-		ql_dbg(ql_dbg_io, vha, 0xff03,
-		    "HOST-ABORT: handle=%d, state=BAD(%d).\n", handle,
-		    cmd->state);
-		dump_stack();
-	}
-
-	cmd->trc_flags |= TRC_FLUSH;
-	ha->tgt.tgt_ops->free_cmd(cmd);
-}
-
 void
 qlt_host_reset_handler(struct qla_hw_data *ha)
 {
@@ -3661,8 +3612,7 @@ qlt_host_reset_handler(struct qla_hw_data *ha)
 		if (!cmd)
 			continue;
 		/* ha->tgt.cmds entry is cleared by qlt_get_cmd. */
-		vha = cmd->vha;
-		qlt_abort_cmd_on_host_reset(vha, cmd);
+		/* To do: abort cmd. */
 	}
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
@@ -3790,7 +3740,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
 		    (!cmd->aborted)) {
 			cmd->trc_flags |= TRC_CTIO_ERR;
 			if (qlt_term_ctio_exchange(vha, ctio, cmd, status))
-				return;
+				goto free_cmd;
 		}
 	}
 skip_term:
@@ -3822,6 +3772,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
 		dump_stack();
 	}
 
+free_cmd:
 	ha->tgt.tgt_ops->free_cmd(cmd);
 }
 
@@ -3931,8 +3882,7 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	qlt_send_term_exchange(vha, NULL, &cmd->atio, 1, 0);
 
-	qlt_decr_num_pend_cmds(vha);
-	percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag);
+	qlt_free_cmd(cmd);
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 061ba85a2168..a8d1da62e6bd 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -361,6 +361,7 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd)
 {
 	struct qla_tgt_cmd *cmd = container_of(se_cmd,
 				struct qla_tgt_cmd, se_cmd);
+	int res;
 
 	if (cmd->aborted) {
 		/* Cmd can loop during Q-full.  tcm_qla2xxx_aborted_task
@@ -373,7 +374,7 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd)
 			cmd->se_cmd.transport_state,
 			cmd->se_cmd.t_state,
 			cmd->se_cmd.se_cmd_flags);
-		return 0;
+		goto aborted;
 	}
 	cmd->trc_flags |= TRC_XFR_RDY;
 	cmd->bufflen = se_cmd->data_length;
@@ -391,7 +392,14 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd)
 	 * qla_target.c:qlt_rdy_to_xfer() will call pci_map_sg() to setup
 	 * the SGL mappings into PCIe memory for incoming FCP WRITE data.
 	 */
-	return qlt_rdy_to_xfer(cmd);
+	res = qlt_rdy_to_xfer(cmd);
+	if (res != -EINTR)
+		return res;
+
+aborted:
+	target_put_sess_cmd(se_cmd);
+	transport_generic_free_cmd(se_cmd, 0);
+	return 0;
 }
 
 static int tcm_qla2xxx_write_pending_status(struct se_cmd *se_cmd)
@@ -488,7 +496,8 @@ static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
 	if (cmd->aborted) {
 		spin_unlock_irqrestore(&cmd->cmd_lock, flags);
 
-		tcm_qla2xxx_free_cmd(cmd);
+		target_put_sess_cmd(&cmd->se_cmd);
+		transport_generic_free_cmd(&cmd->se_cmd, 0);
 		return;
 	}
 	spin_unlock_irqrestore(&cmd->cmd_lock, flags);
@@ -593,6 +602,7 @@ static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd)
 {
 	struct qla_tgt_cmd *cmd = container_of(se_cmd,
 				struct qla_tgt_cmd, se_cmd);
+	int res;
 
 	if (cmd->aborted) {
 		/* Cmd can loop during Q-full.  tcm_qla2xxx_aborted_task
@@ -605,6 +615,7 @@ static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd)
 			cmd->se_cmd.transport_state,
 			cmd->se_cmd.t_state,
 			cmd->se_cmd.se_cmd_flags);
+		transport_generic_free_cmd(se_cmd, 0);
 		return 0;
 	}
 
@@ -624,15 +635,20 @@ static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd)
 	/*
 	 * Now queue completed DATA_IN the qla2xxx LLD and response ring
 	 */
-	return qlt_xmit_response(cmd, QLA_TGT_XMIT_DATA|QLA_TGT_XMIT_STATUS,
+	res = qlt_xmit_response(cmd, QLA_TGT_XMIT_DATA | QLA_TGT_XMIT_STATUS,
 				se_cmd->scsi_status);
+	if (res != 0 && res != -ENOMEM && res != -EAGAIN) {
+		transport_generic_free_cmd(se_cmd, 0);
+		res = 0;
+	}
+	return res;
 }
 
 static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd)
 {
 	struct qla_tgt_cmd *cmd = container_of(se_cmd,
 				struct qla_tgt_cmd, se_cmd);
-	int xmit_type = QLA_TGT_XMIT_STATUS;
+	int xmit_type = QLA_TGT_XMIT_STATUS, res;
 
 	cmd->bufflen = se_cmd->data_length;
 	cmd->sg = NULL;
@@ -662,7 +678,12 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd)
 	/*
 	 * Now queue status response to qla2xxx LLD code and response ring
 	 */
-	return qlt_xmit_response(cmd, xmit_type, se_cmd->scsi_status);
+	res = qlt_xmit_response(cmd, xmit_type, se_cmd->scsi_status);
+	if (res != 0 && res != -ENOMEM && res != -EAGAIN) {
+		transport_generic_free_cmd(se_cmd, 0);
+		res = 0;
+	}
+	return res;
 }
 
 static void tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd)
-- 
2.11.0

--
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