diff options
| author | Lee Duncan <lduncan@suse.com> | 2019-02-25 12:41:30 -0500 |
|---|---|---|
| committer | Martin K. Petersen <martin.petersen@oracle.com> | 2019-03-07 21:37:04 -0500 |
| commit | a656183e6c58a3a4d818278afab522b30a17014c (patch) | |
| tree | cbb8559e07d33ae4234aaae5196501af4e7e9e86 /drivers/scsi | |
| parent | cf9efd5d92365696580a45e0351208eef0ea1562 (diff) | |
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>
Diffstat (limited to 'drivers/scsi')
| -rw-r--r-- | drivers/scsi/libiscsi.c | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index dd314d2b1111..418dbed7618f 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
| @@ -798,7 +798,7 @@ EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); | |||
| 798 | * @datalen: len of buffer | 798 | * @datalen: len of buffer |
| 799 | * | 799 | * |
| 800 | * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and | 800 | * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and |
| 801 | * then completes the command and task. | 801 | * then completes the command and task. called under back_lock |
| 802 | **/ | 802 | **/ |
| 803 | static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 803 | static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
| 804 | struct iscsi_task *task, char *data, | 804 | struct iscsi_task *task, char *data, |
| @@ -894,6 +894,9 @@ out: | |||
| 894 | * @conn: iscsi connection | 894 | * @conn: iscsi connection |
| 895 | * @hdr: iscsi pdu | 895 | * @hdr: iscsi pdu |
| 896 | * @task: scsi command task | 896 | * @task: scsi command task |
| 897 | * | ||
| 898 | * iscsi_data_in_rsp sets up the scsi_cmnd fields based on the data received | ||
| 899 | * then completes the command and task. called under back_lock | ||
| 897 | **/ | 900 | **/ |
| 898 | static void | 901 | static void |
| 899 | iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 902 | 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) | |||
| 978 | return 0; | 981 | return 0; |
| 979 | } | 982 | } |
| 980 | 983 | ||
| 984 | /** | ||
| 985 | * iscsi_nop_out_rsp - SCSI NOP Response processing | ||
| 986 | * @task: scsi command task | ||
| 987 | * @nop: the nop structure | ||
| 988 | * @data: where to put the data | ||
| 989 | * @datalen: length of data | ||
| 990 | * | ||
| 991 | * iscsi_nop_out_rsp handles nop response from use or | ||
| 992 | * from user space. called under back_lock | ||
| 993 | **/ | ||
| 981 | static int iscsi_nop_out_rsp(struct iscsi_task *task, | 994 | static int iscsi_nop_out_rsp(struct iscsi_task *task, |
| 982 | struct iscsi_nopin *nop, char *data, int datalen) | 995 | struct iscsi_nopin *nop, char *data, int datalen) |
| 983 | { | 996 | { |
| @@ -1744,7 +1757,9 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc) | |||
| 1744 | return 0; | 1757 | return 0; |
| 1745 | 1758 | ||
| 1746 | prepd_reject: | 1759 | prepd_reject: |
| 1760 | spin_lock_bh(&session->back_lock); | ||
| 1747 | iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ); | 1761 | iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ); |
| 1762 | spin_unlock_bh(&session->back_lock); | ||
| 1748 | reject: | 1763 | reject: |
| 1749 | spin_unlock_bh(&session->frwd_lock); | 1764 | spin_unlock_bh(&session->frwd_lock); |
| 1750 | ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n", | 1765 | ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n", |
| @@ -1752,7 +1767,9 @@ reject: | |||
| 1752 | return SCSI_MLQUEUE_TARGET_BUSY; | 1767 | return SCSI_MLQUEUE_TARGET_BUSY; |
| 1753 | 1768 | ||
| 1754 | prepd_fault: | 1769 | prepd_fault: |
| 1770 | spin_lock_bh(&session->back_lock); | ||
| 1755 | iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ); | 1771 | iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ); |
| 1772 | spin_unlock_bh(&session->back_lock); | ||
| 1756 | fault: | 1773 | fault: |
| 1757 | spin_unlock_bh(&session->frwd_lock); | 1774 | spin_unlock_bh(&session->frwd_lock); |
| 1758 | ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n", | 1775 | 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) | |||
| 3069 | state = ISCSI_TASK_ABRT_SESS_RECOV; | 3086 | state = ISCSI_TASK_ABRT_SESS_RECOV; |
| 3070 | if (task->state == ISCSI_TASK_PENDING) | 3087 | if (task->state == ISCSI_TASK_PENDING) |
| 3071 | state = ISCSI_TASK_COMPLETED; | 3088 | state = ISCSI_TASK_COMPLETED; |
| 3089 | spin_lock_bh(&session->back_lock); | ||
| 3072 | iscsi_complete_task(task, state); | 3090 | iscsi_complete_task(task, state); |
| 3073 | 3091 | spin_unlock_bh(&session->back_lock); | |
| 3074 | } | 3092 | } |
| 3075 | } | 3093 | } |
| 3076 | 3094 | ||
