]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Mike Christie <michaelc@cs.wisc.edu> |
2 | Date: Tue, 28 Apr 2009 13:38:18 -0400 | |
3 | Subject: libiscsi: fix nop response/reply and session cleanup race | |
4 | References: bnc#499558 | |
5 | ||
6 | If we are responding to a nop from the target by sending our nop, | |
7 | and the session is getting torn down, then iscsi_start_session_recovery | |
8 | could set the conn stop bits while the recv path is sending the nop | |
9 | response and we will hit the bug ons in __iscsi_conn_send_pdu. | |
10 | ||
11 | This has us check the state in __iscsi_conn_send_pdu and fail all | |
12 | incoming mgmt IO if we are not logged in and if the pdu is not login | |
13 | related. It also changes the ordering of the setting of conn stop state | |
14 | bits so they are set after the session state is set (both are set under | |
15 | the session lock). | |
16 | ||
17 | Acked-by: Jean Delvare <jdelvare@suse.de> | |
18 | --- | |
19 | drivers/scsi/libiscsi.c | 11 ++++++++--- | |
20 | 1 file changed, 8 insertions(+), 3 deletions(-) | |
21 | ||
22 | --- a/drivers/scsi/libiscsi.c | |
23 | +++ b/drivers/scsi/libiscsi.c | |
24 | @@ -502,6 +502,9 @@ __iscsi_conn_send_pdu(struct iscsi_conn | |
25 | */ | |
26 | task = conn->login_task; | |
27 | else { | |
28 | + if (session->state != ISCSI_STATE_LOGGED_IN) | |
29 | + return NULL; | |
30 | + | |
31 | BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); | |
32 | BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); | |
33 | ||
34 | @@ -2414,8 +2417,6 @@ static void iscsi_start_session_recovery | |
35 | { | |
36 | int old_stop_stage; | |
37 | ||
38 | - del_timer_sync(&conn->transport_timer); | |
39 | - | |
40 | mutex_lock(&session->eh_mutex); | |
41 | spin_lock_bh(&session->lock); | |
42 | if (conn->stop_stage == STOP_CONN_TERM) { | |
43 | @@ -2433,13 +2434,17 @@ static void iscsi_start_session_recovery | |
44 | session->state = ISCSI_STATE_TERMINATE; | |
45 | else if (conn->stop_stage != STOP_CONN_RECOVER) | |
46 | session->state = ISCSI_STATE_IN_RECOVERY; | |
47 | + spin_unlock_bh(&session->lock); | |
48 | ||
49 | + del_timer_sync(&conn->transport_timer); | |
50 | + iscsi_suspend_tx(conn); | |
51 | + | |
52 | + spin_lock_bh(&session->lock); | |
53 | old_stop_stage = conn->stop_stage; | |
54 | conn->stop_stage = flag; | |
55 | conn->c_stage = ISCSI_CONN_STOPPED; | |
56 | spin_unlock_bh(&session->lock); | |
57 | ||
58 | - iscsi_suspend_tx(conn); | |
59 | /* | |
60 | * for connection level recovery we should not calculate | |
61 | * header digest. conn->hdr_size used for optimization |