Skip to content

Commit 656cffc

Browse files
Mike ChristieJames Bottomley
authored andcommitted
[SCSI] iscsi: fix command requeues during iscsi recovery
Do not flush queues then block session. This will cause commands to needlessly swing around on us and remove goofy recovery_failed field and replace with state value. And do not start recovery from within the host reset function. This causeis too many problems becuase open-iscsi was desinged to call out to userspace then have userpscae decide if we should go into recovery or kill the session. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
1 parent 790f39a commit 656cffc

File tree

3 files changed

+50
-42
lines changed

3 files changed

+50
-42
lines changed

drivers/scsi/libiscsi.c

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,11 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
487487
unsigned long flags;
488488

489489
spin_lock_irqsave(&session->lock, flags);
490+
if (session->state == ISCSI_STATE_FAILED) {
491+
spin_unlock_irqrestore(&session->lock, flags);
492+
return;
493+
}
494+
490495
if (session->conn_cnt == 1 || session->leadconn == conn)
491496
session->state = ISCSI_STATE_FAILED;
492497
spin_unlock_irqrestore(&session->lock, flags);
@@ -612,6 +617,7 @@ enum {
612617
FAILURE_SESSION_FREED,
613618
FAILURE_WINDOW_CLOSED,
614619
FAILURE_SESSION_TERMINATE,
620+
FAILURE_SESSION_IN_RECOVERY,
615621
FAILURE_SESSION_RECOVERY_TIMEOUT,
616622
};
617623

@@ -631,18 +637,30 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
631637

632638
spin_lock(&session->lock);
633639

634-
if (session->state != ISCSI_STATE_LOGGED_IN) {
635-
if (session->recovery_failed) {
636-
reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
637-
goto fault;
638-
} else if (session->state == ISCSI_STATE_FAILED) {
639-
reason = FAILURE_SESSION_FAILED;
640-
goto reject;
641-
} else if (session->state == ISCSI_STATE_TERMINATE) {
642-
reason = FAILURE_SESSION_TERMINATE;
640+
/*
641+
* ISCSI_STATE_FAILED is a temp. state. The recovery
642+
* code will decide what is best to do with command queued
643+
* during this time
644+
*/
645+
if (session->state != ISCSI_STATE_LOGGED_IN &&
646+
session->state != ISCSI_STATE_FAILED) {
647+
/*
648+
* to handle the race between when we set the recovery state
649+
* and block the session we requeue here (commands could
650+
* be entering our queuecommand while a block is starting
651+
* up because the block code is not locked)
652+
*/
653+
if (session->state == ISCSI_STATE_IN_RECOVERY) {
654+
reason = FAILURE_SESSION_IN_RECOVERY;
643655
goto fault;
644656
}
645-
reason = FAILURE_SESSION_FREED;
657+
658+
if (session->state == ISCSI_STATE_RECOVERY_FAILED)
659+
reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
660+
else if (session->state == ISCSI_STATE_TERMINATE)
661+
reason = FAILURE_SESSION_TERMINATE;
662+
else
663+
reason = FAILURE_SESSION_FREED;
646664
goto fault;
647665
}
648666

@@ -728,8 +746,8 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
728746
*/
729747
mtask = conn->login_mtask;
730748
else {
731-
BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
732-
BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
749+
BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
750+
BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
733751

734752
nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
735753
if (!__kfifo_get(session->mgmtpool.queue,
@@ -803,7 +821,7 @@ void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
803821

804822
spin_lock_bh(&session->lock);
805823
if (session->state != ISCSI_STATE_LOGGED_IN) {
806-
session->recovery_failed = 1;
824+
session->state = ISCSI_STATE_RECOVERY_FAILED;
807825
if (conn)
808826
wake_up(&conn->ehwait);
809827
}
@@ -838,20 +856,14 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc)
838856
* we drop the lock here but the leadconn cannot be destoyed while
839857
* we are in the scsi eh
840858
*/
841-
if (fail_session) {
859+
if (fail_session)
842860
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
843-
/*
844-
* if userspace cannot respond then we must kick this off
845-
* here for it
846-
*/
847-
iscsi_start_session_recovery(session, conn, STOP_CONN_RECOVER);
848-
}
849861

850862
debug_scsi("iscsi_eh_host_reset wait for relogin\n");
851863
wait_event_interruptible(conn->ehwait,
852864
session->state == ISCSI_STATE_TERMINATE ||
853865
session->state == ISCSI_STATE_LOGGED_IN ||
854-
session->recovery_failed);
866+
session->state == ISCSI_STATE_RECOVERY_FAILED);
855867
if (signal_pending(current))
856868
flush_signals(current);
857869

@@ -940,8 +952,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
940952
wait_event_interruptible(conn->ehwait,
941953
sc->SCp.phase != session->age ||
942954
session->state != ISCSI_STATE_LOGGED_IN ||
943-
conn->tmabort_state != TMABORT_INITIAL ||
944-
session->recovery_failed);
955+
conn->tmabort_state != TMABORT_INITIAL);
945956
if (signal_pending(current))
946957
flush_signals(current);
947958
del_timer_sync(&conn->tmabort_timer);
@@ -1491,7 +1502,6 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
14911502
conn->stop_stage = 0;
14921503
conn->tmabort_state = TMABORT_INITIAL;
14931504
session->age++;
1494-
session->recovery_failed = 0;
14951505
spin_unlock_bh(&session->lock);
14961506

14971507
iscsi_unblock_session(session_to_cls(session));
@@ -1566,8 +1576,8 @@ static void fail_all_commands(struct iscsi_conn *conn)
15661576
conn->ctask = NULL;
15671577
}
15681578

1569-
void iscsi_start_session_recovery(struct iscsi_session *session,
1570-
struct iscsi_conn *conn, int flag)
1579+
static void iscsi_start_session_recovery(struct iscsi_session *session,
1580+
struct iscsi_conn *conn, int flag)
15711581
{
15721582
int old_stop_stage;
15731583

@@ -1597,19 +1607,10 @@ void iscsi_start_session_recovery(struct iscsi_session *session,
15971607
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
15981608

15991609
if (session->conn_cnt == 0 || session->leadconn == conn)
1600-
session->state = ISCSI_STATE_FAILED;
1610+
session->state = ISCSI_STATE_IN_RECOVERY;
16011611

16021612
spin_unlock_bh(&session->lock);
16031613

1604-
session->tt->terminate_conn(conn);
1605-
/*
1606-
* flush queues.
1607-
*/
1608-
spin_lock_bh(&session->lock);
1609-
fail_all_commands(conn);
1610-
flush_control_queues(session, conn);
1611-
spin_unlock_bh(&session->lock);
1612-
16131614
/*
16141615
* for connection level recovery we should not calculate
16151616
* header digest. conn->hdr_size used for optimization
@@ -1619,18 +1620,26 @@ void iscsi_start_session_recovery(struct iscsi_session *session,
16191620
if (flag == STOP_CONN_RECOVER) {
16201621
conn->hdrdgst_en = 0;
16211622
conn->datadgst_en = 0;
1622-
16231623
/*
16241624
* if this is called from the eh and and from userspace
16251625
* then we only need to block once.
16261626
*/
1627-
if (session->state == ISCSI_STATE_FAILED &&
1627+
if (session->state == ISCSI_STATE_IN_RECOVERY &&
16281628
old_stop_stage != STOP_CONN_RECOVER)
16291629
iscsi_block_session(session_to_cls(session));
16301630
}
1631+
1632+
session->tt->terminate_conn(conn);
1633+
/*
1634+
* flush queues.
1635+
*/
1636+
spin_lock_bh(&session->lock);
1637+
fail_all_commands(conn);
1638+
flush_control_queues(session, conn);
1639+
spin_unlock_bh(&session->lock);
1640+
16311641
mutex_unlock(&conn->xmitmutex);
16321642
}
1633-
EXPORT_SYMBOL_GPL(iscsi_start_session_recovery);
16341643

16351644
void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
16361645
{

include/scsi/libiscsi.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,6 @@ struct iscsi_session {
210210
* - mgmtpool, *
211211
* - r2tpool */
212212
int state; /* session state */
213-
int recovery_failed;
214213
struct list_head item;
215214
int conn_cnt;
216215
int age; /* counts session re-opens */
@@ -241,8 +240,6 @@ iscsi_session_setup(struct iscsi_transport *, struct scsi_transport_template *,
241240
int, int, uint32_t, uint32_t *);
242241
extern void iscsi_session_teardown(struct iscsi_cls_session *);
243242
extern struct iscsi_session *class_to_transport_session(struct iscsi_cls_session *);
244-
extern void iscsi_start_session_recovery(struct iscsi_session *,
245-
struct iscsi_conn *, int);
246243
extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);
247244

248245
#define session_to_cls(_sess) \

include/scsi/scsi_transport_iscsi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ struct iscsi_cls_conn {
173173
#define ISCSI_STATE_LOGGED_IN 2
174174
#define ISCSI_STATE_FAILED 3
175175
#define ISCSI_STATE_TERMINATE 4
176+
#define ISCSI_STATE_IN_RECOVERY 5
177+
#define ISCSI_STATE_RECOVERY_FAILED 6
176178

177179
struct iscsi_cls_session {
178180
struct list_head sess_list; /* item in session_list */

0 commit comments

Comments
 (0)