mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-03 17:14:14 +08:00
scsi: libiscsi: Hold back_lock when calling iscsi_complete_task
If there is an error queueing an iscsi command in iscsi_queuecommand(), for example if the transport fails to take the command in sessuin->tt->xmit_task(), then the error path can call iscsi_complete_task() without first aquiring the back_lock as required. This can lead to things like ITT pool can get corrupt, resulting in duplicate ITTs being sent out. The solution is to hold the back_lock around iscsi_complete_task() calls, and to add a little commenting to help others understand when back_lock must be held. Signed-off-by: Lee Duncan <lduncan@suse.com> Acked-by: Chris Leech <cleech@redhat.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
cf9efd5d92
commit
a656183e6c
@ -798,7 +798,7 @@ EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
|
|||||||
* @datalen: len of buffer
|
* @datalen: len of buffer
|
||||||
*
|
*
|
||||||
* iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and
|
* iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and
|
||||||
* then completes the command and task.
|
* then completes the command and task. called under back_lock
|
||||||
**/
|
**/
|
||||||
static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
|
static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
|
||||||
struct iscsi_task *task, char *data,
|
struct iscsi_task *task, char *data,
|
||||||
@ -894,6 +894,9 @@ out:
|
|||||||
* @conn: iscsi connection
|
* @conn: iscsi connection
|
||||||
* @hdr: iscsi pdu
|
* @hdr: iscsi pdu
|
||||||
* @task: scsi command task
|
* @task: scsi command task
|
||||||
|
*
|
||||||
|
* iscsi_data_in_rsp sets up the scsi_cmnd fields based on the data received
|
||||||
|
* then completes the command and task. called under back_lock
|
||||||
**/
|
**/
|
||||||
static void
|
static void
|
||||||
iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
|
iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
|
||||||
@ -978,6 +981,16 @@ static int iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iscsi_nop_out_rsp - SCSI NOP Response processing
|
||||||
|
* @task: scsi command task
|
||||||
|
* @nop: the nop structure
|
||||||
|
* @data: where to put the data
|
||||||
|
* @datalen: length of data
|
||||||
|
*
|
||||||
|
* iscsi_nop_out_rsp handles nop response from use or
|
||||||
|
* from user space. called under back_lock
|
||||||
|
**/
|
||||||
static int iscsi_nop_out_rsp(struct iscsi_task *task,
|
static int iscsi_nop_out_rsp(struct iscsi_task *task,
|
||||||
struct iscsi_nopin *nop, char *data, int datalen)
|
struct iscsi_nopin *nop, char *data, int datalen)
|
||||||
{
|
{
|
||||||
@ -1744,7 +1757,9 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
prepd_reject:
|
prepd_reject:
|
||||||
|
spin_lock_bh(&session->back_lock);
|
||||||
iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
|
iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
|
||||||
|
spin_unlock_bh(&session->back_lock);
|
||||||
reject:
|
reject:
|
||||||
spin_unlock_bh(&session->frwd_lock);
|
spin_unlock_bh(&session->frwd_lock);
|
||||||
ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
|
ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
|
||||||
@ -1752,7 +1767,9 @@ reject:
|
|||||||
return SCSI_MLQUEUE_TARGET_BUSY;
|
return SCSI_MLQUEUE_TARGET_BUSY;
|
||||||
|
|
||||||
prepd_fault:
|
prepd_fault:
|
||||||
|
spin_lock_bh(&session->back_lock);
|
||||||
iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
|
iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
|
||||||
|
spin_unlock_bh(&session->back_lock);
|
||||||
fault:
|
fault:
|
||||||
spin_unlock_bh(&session->frwd_lock);
|
spin_unlock_bh(&session->frwd_lock);
|
||||||
ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
|
ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
|
||||||
@ -3069,8 +3086,9 @@ fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn)
|
|||||||
state = ISCSI_TASK_ABRT_SESS_RECOV;
|
state = ISCSI_TASK_ABRT_SESS_RECOV;
|
||||||
if (task->state == ISCSI_TASK_PENDING)
|
if (task->state == ISCSI_TASK_PENDING)
|
||||||
state = ISCSI_TASK_COMPLETED;
|
state = ISCSI_TASK_COMPLETED;
|
||||||
|
spin_lock_bh(&session->back_lock);
|
||||||
iscsi_complete_task(task, state);
|
iscsi_complete_task(task, state);
|
||||||
|
spin_unlock_bh(&session->back_lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user