RE: [EXT] [PATCH 04/13] scsi: qedi: fix abort vs cmd re-use race

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

 




> -----Original Message-----
> From: Mike Christie <michael.christie@xxxxxxxxxx>
> Sent: Sunday, April 11, 2021 12:10 AM
> To: lduncan@xxxxxxxx; martin.petersen@xxxxxxxxxx; Manish Rangankar
> <mrangankar@xxxxxxxxxxx>; Santosh Vernekar <svernekar@xxxxxxxxxxx>;
> linux-scsi@xxxxxxxxxxxxxxx; jejb@xxxxxxxxxxxxx
> Cc: Mike Christie <michael.christie@xxxxxxxxxx>
> Subject: [EXT] [PATCH 04/13] scsi: qedi: fix abort vs cmd re-use race
> 
> External Email
> 
> ----------------------------------------------------------------------
> If the scsi cmd completes after qedi_tmf_work calls iscsi_itt_to_task then the
> qedi qedi_cmd->task_id could be freed and used for another cmd. If we then call
> qedi_iscsi_cleanup_task with that task_id we will be cleaning up the wrong cmd.
> 
> This patch has us wait to release the task_id until the last put has been done on
> the iscsi_task. Because libiscsi grabs a ref to the task when sending the abort,
> we know that for the non abort timeout case that the task_id we are
> referencing is for the cmd that was supposed to be aborted.
> 
> The next patch will fix the case where the abort timesout while we are running
> qedi_tmf_work.
> 
> Signed-off-by: Mike Christie <michael.christie@xxxxxxxxxx>
> ---
>  drivers/scsi/qedi/qedi_fw.c    | 13 -------------
>  drivers/scsi/qedi/qedi_iscsi.c | 20 +++++++++++++++++---
>  2 files changed, 17 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c index
> cf57b4e49700..ad4357e4c15d 100644
> --- a/drivers/scsi/qedi/qedi_fw.c
> +++ b/drivers/scsi/qedi/qedi_fw.c
> @@ -73,7 +73,6 @@ static void qedi_process_logout_resp(struct qedi_ctx
> *qedi,
>  	spin_unlock(&qedi_conn->list_lock);
> 
>  	cmd->state = RESPONSE_RECEIVED;
> -	qedi_clear_task_idx(qedi, cmd->task_id);
>  	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
> 
>  	spin_unlock(&session->back_lock);
> @@ -138,7 +137,6 @@ static void qedi_process_text_resp(struct qedi_ctx
> *qedi,
>  	spin_unlock(&qedi_conn->list_lock);
> 
>  	cmd->state = RESPONSE_RECEIVED;
> -	qedi_clear_task_idx(qedi, cmd->task_id);
> 
>  	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr,
>  			     qedi_conn->gen_pdu.resp_buf,
> @@ -164,13 +162,11 @@ static void qedi_tmf_resp_work(struct work_struct
> *work)
>  	iscsi_block_session(session->cls_session);
>  	rval = qedi_cleanup_all_io(qedi, qedi_conn, qedi_cmd->task, true);
>  	if (rval) {
> -		qedi_clear_task_idx(qedi, qedi_cmd->task_id);
>  		iscsi_unblock_session(session->cls_session);
>  		goto exit_tmf_resp;
>  	}
> 
>  	iscsi_unblock_session(session->cls_session);
> -	qedi_clear_task_idx(qedi, qedi_cmd->task_id);
> 
>  	spin_lock(&session->back_lock);
>  	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr, NULL, 0);
> @@ -245,8 +241,6 @@ static void qedi_process_tmf_resp(struct qedi_ctx
> *qedi,
>  		goto unblock_sess;
>  	}
> 
> -	qedi_clear_task_idx(qedi, qedi_cmd->task_id);
> -
>  	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr, NULL, 0);
>  	kfree(resp_hdr_ptr);
> 
> @@ -314,7 +308,6 @@ static void qedi_process_login_resp(struct qedi_ctx
> *qedi,
>  		  "Freeing tid=0x%x for cid=0x%x\n",
>  		  cmd->task_id, qedi_conn->iscsi_conn_id);
>  	cmd->state = RESPONSE_RECEIVED;
> -	qedi_clear_task_idx(qedi, cmd->task_id);
>  }
> 
>  static void qedi_get_rq_bdq_buf(struct qedi_ctx *qedi, @@ -468,7 +461,6 @@
> static int qedi_process_nopin_mesg(struct qedi_ctx *qedi,
>  		}
> 
>  		spin_unlock(&qedi_conn->list_lock);
> -		qedi_clear_task_idx(qedi, cmd->task_id);
>  	}
> 
>  done:
> @@ -673,7 +665,6 @@ static void qedi_scsi_completion(struct qedi_ctx *qedi,
>  	if (qedi_io_tracing)
>  		qedi_trace_io(qedi, task, cmd->task_id, QEDI_IO_TRACE_RSP);
> 
> -	qedi_clear_task_idx(qedi, cmd->task_id);
>  	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
>  			     conn->data, datalen);
>  error:
> @@ -730,7 +721,6 @@ static void qedi_process_nopin_local_cmpl(struct
> qedi_ctx *qedi,
>  		  cqe->itid, cmd->task_id);
> 
>  	cmd->state = RESPONSE_RECEIVED;
> -	qedi_clear_task_idx(qedi, cmd->task_id);
> 
>  	spin_lock_bh(&session->back_lock);
>  	__iscsi_put_task(task);
> @@ -821,8 +811,6 @@ static void qedi_process_cmd_cleanup_resp(struct
> qedi_ctx *qedi,
>  			if (qedi_cmd->state == CLEANUP_WAIT_FAILED)
>  				qedi_cmd->state = CLEANUP_RECV;
> 
> -			qedi_clear_task_idx(qedi_conn->qedi, rtid);
> -
>  			spin_lock(&qedi_conn->list_lock);
>  			if (likely(dbg_cmd->io_cmd_in_list)) {
>  				dbg_cmd->io_cmd_in_list = false;
> @@ -856,7 +844,6 @@ static void qedi_process_cmd_cleanup_resp(struct
> qedi_ctx *qedi,
>  		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID,
>  			  "Freeing tid=0x%x for cid=0x%x\n",
>  			  cqe->itid, qedi_conn->iscsi_conn_id);
> -		qedi_clear_task_idx(qedi_conn->qedi, cqe->itid);
> 
>  	} else {
>  		qedi_get_proto_itt(qedi, cqe->itid, &ptmp_itt); diff --git
> a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c index
> 08c05403cd72..d1da34a938da 100644
> --- a/drivers/scsi/qedi/qedi_iscsi.c
> +++ b/drivers/scsi/qedi/qedi_iscsi.c
> @@ -772,7 +772,6 @@ static int qedi_mtask_xmit(struct iscsi_conn *conn,
> struct iscsi_task *task)
>  	}
> 
>  	cmd->conn = conn->dd_data;
> -	cmd->scsi_cmd = NULL;
>  	return qedi_iscsi_send_generic_request(task);
>  }
> 
> @@ -783,6 +782,10 @@ static int qedi_task_xmit(struct iscsi_task *task)
>  	struct qedi_cmd *cmd = task->dd_data;
>  	struct scsi_cmnd *sc = task->sc;
> 
> +	/* Clear now so in cleanup_task we know it didn't make it */
> +	cmd->scsi_cmd = NULL;
> +	cmd->task_id = -1;
> +
>  	if (test_bit(QEDI_IN_SHUTDOWN, &qedi_conn->qedi->flags))
>  		return -ENODEV;
> 
> @@ -1383,13 +1386,24 @@ static umode_t qedi_attr_is_visible(int
> param_type, int param)
> 
>  static void qedi_cleanup_task(struct iscsi_task *task)  {
> -	if (!task->sc || task->state == ISCSI_TASK_PENDING) {
> +	struct qedi_cmd *cmd;
> +
> +	if (task->state == ISCSI_TASK_PENDING) {
>  		QEDI_INFO(NULL, QEDI_LOG_IO, "Returning ref_cnt=%d\n",
>  			  refcount_read(&task->refcount));
>  		return;
>  	}
> 
> -	qedi_iscsi_unmap_sg_list(task->dd_data);
> +	if (task->sc)
> +		qedi_iscsi_unmap_sg_list(task->dd_data);
> +
> +	cmd = task->dd_data;
> +	if (cmd->task_id != -1)
> +		qedi_clear_task_idx(iscsi_host_priv(task->conn->session->host),
> +				    cmd->task_id);
> +
> +	cmd->task_id = -1;
> +	cmd->scsi_cmd = NULL;
>  }
> 
>  struct iscsi_transport qedi_iscsi_transport = {
> --
> 2.25.1

Reviewed-by: Manish Rangankar <mrangankar@xxxxxxxxxxx>





[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