aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libiscsi.c
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2009-05-13 18:57:43 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-05-23 16:44:11 -0400
commit26013ad4c43f49a038a6489c35e9b901491339fe (patch)
treec5f9b4a8c73de58b08ac9c072b81d27de3e1dd3b /drivers/scsi/libiscsi.c
parentedbc9aa0580c0aca96ac8d11bfb2defa81d91bb3 (diff)
[SCSI] libiscsi: fix nop response/reply and session cleanup race
If we are responding to a nop from the target by sending our nop, and the session is getting torn down, then iscsi_start_session_recovery could set the conn stop bits while the recv path is sending the nop response and we will hit the bug ons in __iscsi_conn_send_pdu. This has us check the state in __iscsi_conn_send_pdu and fail all incoming mgmt IO if we are not logged in and if the pdu is not login related. It also changes the ordering of the setting of conn stop state bits so they are set after the session state is set (both are set under the session lock). Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/libiscsi.c')
-rw-r--r--drivers/scsi/libiscsi.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 047543cd3fc1..212fe2027a8c 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -546,6 +546,9 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
546 */ 546 */
547 task = conn->login_task; 547 task = conn->login_task;
548 else { 548 else {
549 if (session->state != ISCSI_STATE_LOGGED_IN)
550 return NULL;
551
549 BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); 552 BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
550 BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); 553 BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
551 554
@@ -2566,8 +2569,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
2566{ 2569{
2567 int old_stop_stage; 2570 int old_stop_stage;
2568 2571
2569 del_timer_sync(&conn->transport_timer);
2570
2571 mutex_lock(&session->eh_mutex); 2572 mutex_lock(&session->eh_mutex);
2572 spin_lock_bh(&session->lock); 2573 spin_lock_bh(&session->lock);
2573 if (conn->stop_stage == STOP_CONN_TERM) { 2574 if (conn->stop_stage == STOP_CONN_TERM) {
@@ -2585,13 +2586,17 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
2585 session->state = ISCSI_STATE_TERMINATE; 2586 session->state = ISCSI_STATE_TERMINATE;
2586 else if (conn->stop_stage != STOP_CONN_RECOVER) 2587 else if (conn->stop_stage != STOP_CONN_RECOVER)
2587 session->state = ISCSI_STATE_IN_RECOVERY; 2588 session->state = ISCSI_STATE_IN_RECOVERY;
2589 spin_unlock_bh(&session->lock);
2588 2590
2591 del_timer_sync(&conn->transport_timer);
2592 iscsi_suspend_tx(conn);
2593
2594 spin_lock_bh(&session->lock);
2589 old_stop_stage = conn->stop_stage; 2595 old_stop_stage = conn->stop_stage;
2590 conn->stop_stage = flag; 2596 conn->stop_stage = flag;
2591 conn->c_stage = ISCSI_CONN_STOPPED; 2597 conn->c_stage = ISCSI_CONN_STOPPED;
2592 spin_unlock_bh(&session->lock); 2598 spin_unlock_bh(&session->lock);
2593 2599
2594 iscsi_suspend_tx(conn);
2595 /* 2600 /*
2596 * for connection level recovery we should not calculate 2601 * for connection level recovery we should not calculate
2597 * header digest. conn->hdr_size used for optimization 2602 * header digest. conn->hdr_size used for optimization