aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2007-08-15 02:38:30 -0400
committerJames Bottomley <jejb@mulgrave.localdomain>2007-08-15 14:09:21 -0400
commit6724add1b5cfb020ba8f5532efe430d1ccd5fc30 (patch)
tree4c1f0de4c56835934d844ac20cc42a54ee19ce6f /drivers/scsi
parent96809f1b15eddae2325b2ab78e6f931edc969074 (diff)
[SCSI] libiscsi: sync up iscsi and scsi eh's access to the connection
The iscsi eh could be tearing down the session/connection while the scsi eh is still sending task management functions. If when we drop the session lock to grab the recv lock, the iscsi eh tears down the connection we will oops. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/libiscsi.c54
1 files changed, 43 insertions, 11 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index f5915d4d63d9..efceed451b46 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1056,7 +1056,9 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
1056 ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, 1056 ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
1057 NULL, 0); 1057 NULL, 0);
1058 if (!ctask->mtask) { 1058 if (!ctask->mtask) {
1059 spin_unlock_bh(&session->lock);
1059 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 1060 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
1061 spin_lock_bh(&session->lock)
1060 debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt); 1062 debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt);
1061 return -EPERM; 1063 return -EPERM;
1062 } 1064 }
@@ -1073,6 +1075,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
1073 debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt); 1075 debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt);
1074 } 1076 }
1075 spin_unlock_bh(&session->lock); 1077 spin_unlock_bh(&session->lock);
1078 mutex_unlock(&session->eh_mutex);
1076 scsi_queue_work(session->host, &conn->xmitwork); 1079 scsi_queue_work(session->host, &conn->xmitwork);
1077 1080
1078 /* 1081 /*
@@ -1090,6 +1093,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
1090 if (signal_pending(current)) 1093 if (signal_pending(current))
1091 flush_signals(current); 1094 flush_signals(current);
1092 del_timer_sync(&conn->tmabort_timer); 1095 del_timer_sync(&conn->tmabort_timer);
1096 mutex_lock(&session->eh_mutex);
1093 spin_lock_bh(&session->lock); 1097 spin_lock_bh(&session->lock);
1094 return 0; 1098 return 0;
1095} 1099}
@@ -1165,31 +1169,45 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
1165 __iscsi_put_ctask(ctask); 1169 __iscsi_put_ctask(ctask);
1166} 1170}
1167 1171
1172static void iscsi_suspend_tx(struct iscsi_conn *conn)
1173{
1174 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1175 scsi_flush_work(conn->session->host);
1176}
1177
1178static void iscsi_start_tx(struct iscsi_conn *conn)
1179{
1180 clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1181 scsi_queue_work(conn->session->host, &conn->xmitwork);
1182}
1183
1168int iscsi_eh_abort(struct scsi_cmnd *sc) 1184int iscsi_eh_abort(struct scsi_cmnd *sc)
1169{ 1185{
1186 struct Scsi_Host *host = sc->device->host;
1187 struct iscsi_session *session = iscsi_hostdata(host->hostdata);
1170 struct iscsi_cmd_task *ctask; 1188 struct iscsi_cmd_task *ctask;
1171 struct iscsi_conn *conn; 1189 struct iscsi_conn *conn;
1172 struct iscsi_session *session;
1173 int rc; 1190 int rc;
1174 1191
1192 mutex_lock(&session->eh_mutex);
1193 spin_lock_bh(&session->lock);
1175 /* 1194 /*
1176 * if session was ISCSI_STATE_IN_RECOVERY then we may not have 1195 * if session was ISCSI_STATE_IN_RECOVERY then we may not have
1177 * got the command. 1196 * got the command.
1178 */ 1197 */
1179 if (!sc->SCp.ptr) { 1198 if (!sc->SCp.ptr) {
1180 debug_scsi("sc never reached iscsi layer or it completed.\n"); 1199 debug_scsi("sc never reached iscsi layer or it completed.\n");
1200 spin_unlock_bh(&session->lock);
1201 mutex_unlock(&session->eh_mutex);
1181 return SUCCESS; 1202 return SUCCESS;
1182 } 1203 }
1183 1204
1184 ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; 1205 ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
1185 conn = ctask->conn; 1206 conn = ctask->conn;
1186 session = conn->session;
1187 1207
1188 conn->eh_abort_cnt++; 1208 conn->eh_abort_cnt++;
1189 debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); 1209 debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
1190 1210
1191 spin_lock_bh(&session->lock);
1192
1193 /* 1211 /*
1194 * If we are not logged in or we have started a new session 1212 * If we are not logged in or we have started a new session
1195 * then let the host reset code handle this 1213 * then let the host reset code handle this
@@ -1226,6 +1244,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
1226 switch (conn->tmabort_state) { 1244 switch (conn->tmabort_state) {
1227 case TMABORT_SUCCESS: 1245 case TMABORT_SUCCESS:
1228 spin_unlock_bh(&session->lock); 1246 spin_unlock_bh(&session->lock);
1247 iscsi_suspend_tx(conn);
1229 /* 1248 /*
1230 * clean up task if aborted. grab the recv lock as a writer 1249 * clean up task if aborted. grab the recv lock as a writer
1231 */ 1250 */
@@ -1234,11 +1253,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
1234 fail_command(conn, ctask, DID_ABORT << 16); 1253 fail_command(conn, ctask, DID_ABORT << 16);
1235 spin_unlock(&session->lock); 1254 spin_unlock(&session->lock);
1236 write_unlock_bh(conn->recv_lock); 1255 write_unlock_bh(conn->recv_lock);
1237 /* 1256 iscsi_start_tx(conn);
1238 * make sure xmit thread is not still touching the
1239 * ctask/scsi_cmnd
1240 */
1241 scsi_flush_work(session->host);
1242 goto success_unlocked; 1257 goto success_unlocked;
1243 case TMABORT_NOT_FOUND: 1258 case TMABORT_NOT_FOUND:
1244 if (!ctask->sc) { 1259 if (!ctask->sc) {
@@ -1258,12 +1273,14 @@ success:
1258 spin_unlock_bh(&session->lock); 1273 spin_unlock_bh(&session->lock);
1259success_unlocked: 1274success_unlocked:
1260 debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); 1275 debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
1276 mutex_unlock(&session->eh_mutex);
1261 return SUCCESS; 1277 return SUCCESS;
1262 1278
1263failed: 1279failed:
1264 spin_unlock_bh(&session->lock); 1280 spin_unlock_bh(&session->lock);
1265failed_unlocked: 1281failed_unlocked:
1266 debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); 1282 debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
1283 mutex_unlock(&session->eh_mutex);
1267 return FAILED; 1284 return FAILED;
1268} 1285}
1269EXPORT_SYMBOL_GPL(iscsi_eh_abort); 1286EXPORT_SYMBOL_GPL(iscsi_eh_abort);
@@ -1410,6 +1427,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
1410 session->max_cmdsn = initial_cmdsn + 1; 1427 session->max_cmdsn = initial_cmdsn + 1;
1411 session->max_r2t = 1; 1428 session->max_r2t = 1;
1412 session->tt = iscsit; 1429 session->tt = iscsit;
1430 mutex_init(&session->eh_mutex);
1413 1431
1414 /* initialize SCSI PDU commands pool */ 1432 /* initialize SCSI PDU commands pool */
1415 if (iscsi_pool_init(&session->cmdpool, session->cmds_max, 1433 if (iscsi_pool_init(&session->cmdpool, session->cmds_max,
@@ -1743,9 +1761,22 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
1743{ 1761{
1744 int old_stop_stage; 1762 int old_stop_stage;
1745 1763
1764 mutex_lock(&session->eh_mutex);
1746 spin_lock_bh(&session->lock); 1765 spin_lock_bh(&session->lock);
1747 if (conn->stop_stage == STOP_CONN_TERM) { 1766 if (conn->stop_stage == STOP_CONN_TERM) {
1748 spin_unlock_bh(&session->lock); 1767 spin_unlock_bh(&session->lock);
1768 mutex_unlock(&session->eh_mutex);
1769 return;
1770 }
1771
1772 /*
1773 * The LLD either freed/unset the lock on us, or userspace called
1774 * stop but did not create a proper connection (connection was never
1775 * bound or it was unbound then stop was called).
1776 */
1777 if (!conn->recv_lock) {
1778 spin_unlock_bh(&session->lock);
1779 mutex_unlock(&session->eh_mutex);
1749 return; 1780 return;
1750 } 1781 }
1751 1782
@@ -1762,9 +1793,9 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
1762 old_stop_stage = conn->stop_stage; 1793 old_stop_stage = conn->stop_stage;
1763 conn->stop_stage = flag; 1794 conn->stop_stage = flag;
1764 conn->c_stage = ISCSI_CONN_STOPPED; 1795 conn->c_stage = ISCSI_CONN_STOPPED;
1765 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1766 spin_unlock_bh(&session->lock); 1796 spin_unlock_bh(&session->lock);
1767 scsi_flush_work(session->host); 1797
1798 iscsi_suspend_tx(conn);
1768 1799
1769 write_lock_bh(conn->recv_lock); 1800 write_lock_bh(conn->recv_lock);
1770 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); 1801 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
@@ -1793,6 +1824,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
1793 fail_all_commands(conn); 1824 fail_all_commands(conn);
1794 flush_control_queues(session, conn); 1825 flush_control_queues(session, conn);
1795 spin_unlock_bh(&session->lock); 1826 spin_unlock_bh(&session->lock);
1827 mutex_unlock(&session->eh_mutex);
1796} 1828}
1797 1829
1798void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) 1830void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)