Skip to content

Commit

Permalink
[SCSI] libiscsi: do not block session during logout
Browse files Browse the repository at this point in the history
There is not need to block the session during logout. Since
we are going to fail the commands that were blocked just fail them
immediately instead.

Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
  • Loading branch information
Mike Christie authored and James Bottomley committed Jan 12, 2008
1 parent 6320377 commit b3a7ea8
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 76 deletions.
4 changes: 1 addition & 3 deletions drivers/infiniband/ulp/iser/iser_initiator.c
Original file line number Diff line number Diff line change
Expand Up @@ -621,9 +621,7 @@ void iser_snd_completion(struct iser_desc *tx_desc)
struct iscsi_session *session = conn->session;

spin_lock(&conn->session->lock);
list_del(&mtask->running);
__kfifo_put(session->mgmtpool.queue, (void*)&mtask,
sizeof(void*));
iscsi_free_mgmt_task(conn, mtask);
spin_unlock(&session->lock);
}
}
Expand Down
4 changes: 1 addition & 3 deletions drivers/scsi/iscsi_tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1349,9 +1349,7 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
struct iscsi_session *session = conn->session;

spin_lock_bh(&session->lock);
list_del(&conn->mtask->running);
__kfifo_put(session->mgmtpool.queue, (void*)&conn->mtask,
sizeof(void*));
iscsi_free_mgmt_task(conn, mtask);
spin_unlock_bh(&session->lock);
}
return 0;
Expand Down
153 changes: 83 additions & 70 deletions drivers/scsi/libiscsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@
#include <scsi/scsi_transport_iscsi.h>
#include <scsi/libiscsi.h>

static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
int err);

struct iscsi_session *
class_to_transport_session(struct iscsi_cls_session *cls_session)
{
Expand Down Expand Up @@ -274,6 +271,53 @@ static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask)
iscsi_complete_command(ctask);
}

/*
* session lock must be held
*/
static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
int err)
{
struct scsi_cmnd *sc;

sc = ctask->sc;
if (!sc)
return;

if (ctask->state == ISCSI_TASK_PENDING)
/*
* cmd never made it to the xmit thread, so we should not count
* the cmd in the sequencing
*/
conn->session->queued_cmdsn--;
else
conn->session->tt->cleanup_cmd_task(conn, ctask);

sc->result = err;
scsi_set_resid(sc, scsi_bufflen(sc));
if (conn->ctask == ctask)
conn->ctask = NULL;
/* release ref from queuecommand */
__iscsi_put_ctask(ctask);
}

/**
* iscsi_free_mgmt_task - return mgmt task back to pool
* @conn: iscsi connection
* @mtask: mtask
*
* Must be called with session lock.
*/
void iscsi_free_mgmt_task(struct iscsi_conn *conn,
struct iscsi_mgmt_task *mtask)
{
list_del_init(&mtask->running);
if (conn->login_mtask == mtask)
return;
__kfifo_put(conn->session->mgmtpool.queue,
(void*)&mtask, sizeof(void*));
}
EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task);

/**
* iscsi_cmd_rsp - SCSI Command Response processing
* @conn: iscsi connection
Expand Down Expand Up @@ -464,10 +508,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
*/
if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
rc = ISCSI_ERR_CONN_FAILED;
list_del_init(&mtask->running);
if (conn->login_mtask != mtask)
__kfifo_put(session->mgmtpool.queue,
(void*)&mtask, sizeof(void*));
iscsi_free_mgmt_task(conn, mtask);
break;
case ISCSI_OP_SCSI_TMFUNC_RSP:
if (datalen) {
Expand All @@ -476,6 +517,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
}

iscsi_tmf_rsp(conn, hdr);
iscsi_free_mgmt_task(conn, mtask);
break;
case ISCSI_OP_NOOP_IN:
if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
Expand All @@ -486,9 +528,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,

if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
rc = ISCSI_ERR_CONN_FAILED;
list_del_init(&mtask->running);
__kfifo_put(session->mgmtpool.queue,
(void*)&mtask, sizeof(void*));
iscsi_free_mgmt_task(conn, mtask);
break;
default:
rc = ISCSI_ERR_BAD_OPCODE;
Expand Down Expand Up @@ -650,26 +690,19 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn,
static int iscsi_xmit_mtask(struct iscsi_conn *conn)
{
struct iscsi_hdr *hdr = conn->mtask->hdr;
int rc, was_logout = 0;
int rc;

if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT)
conn->session->state = ISCSI_STATE_LOGGING_OUT;
spin_unlock_bh(&conn->session->lock);
if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) {
conn->session->state = ISCSI_STATE_IN_RECOVERY;
iscsi_block_session(session_to_cls(conn->session));
was_logout = 1;
}

rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask);
spin_lock_bh(&conn->session->lock);
if (rc)
return rc;

/* done with this in-progress mtask */
conn->mtask = NULL;

if (was_logout) {
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
return -ENODATA;
}
return 0;
}

Expand Down Expand Up @@ -763,6 +796,12 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
while (!list_empty(&conn->mgmtqueue)) {
conn->mtask = list_entry(conn->mgmtqueue.next,
struct iscsi_mgmt_task, running);
if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
iscsi_free_mgmt_task(conn, conn->mtask);
conn->mtask = NULL;
continue;
}

iscsi_prep_mtask(conn, conn->mtask);
list_move_tail(conn->mgmtqueue.next, &conn->mgmt_run_list);
rc = iscsi_xmit_mtask(conn);
Expand All @@ -777,6 +816,10 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)

conn->ctask = list_entry(conn->xmitqueue.next,
struct iscsi_cmd_task, running);
if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
fail_command(conn, conn->ctask, DID_NO_CONNECT << 16);
continue;
}
if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) {
fail_command(conn, conn->ctask, DID_ABORT << 16);
continue;
Expand All @@ -800,6 +843,12 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL)
break;

/*
* we always do fastlogout - conn stop code will clean up.
*/
if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
break;

conn->ctask = list_entry(conn->requeue.next,
struct iscsi_cmd_task, running);
conn->ctask->state = ISCSI_TASK_RUNNING;
Expand Down Expand Up @@ -842,6 +891,7 @@ enum {
FAILURE_SESSION_TERMINATE,
FAILURE_SESSION_IN_RECOVERY,
FAILURE_SESSION_RECOVERY_TIMEOUT,
FAILURE_SESSION_LOGGING_OUT,
};

int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
Expand Down Expand Up @@ -879,12 +929,19 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
goto reject;
}

if (session->state == ISCSI_STATE_RECOVERY_FAILED)
switch (session->state) {
case ISCSI_STATE_RECOVERY_FAILED:
reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
else if (session->state == ISCSI_STATE_TERMINATE)
break;
case ISCSI_STATE_TERMINATE:
reason = FAILURE_SESSION_TERMINATE;
else
break;
case ISCSI_STATE_LOGGING_OUT:
reason = FAILURE_SESSION_LOGGING_OUT;
break;
default:
reason = FAILURE_SESSION_FREED;
}
goto fault;
}

Expand Down Expand Up @@ -1120,44 +1177,9 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
if (age != session->age ||
session->state != ISCSI_STATE_LOGGED_IN)
return -ENOTCONN;

if (!list_empty(&mtask->running)) {
list_del_init(&mtask->running);
__kfifo_put(session->mgmtpool.queue, (void*)&mtask,
sizeof(void*));
}
return 0;
}

/*
* session lock must be held
*/
static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
int err)
{
struct scsi_cmnd *sc;

sc = ctask->sc;
if (!sc)
return;

if (ctask->state == ISCSI_TASK_PENDING)
/*
* cmd never made it to the xmit thread, so we should not count
* the cmd in the sequencing
*/
conn->session->queued_cmdsn--;
else
conn->session->tt->cleanup_cmd_task(conn, ctask);

sc->result = err;
scsi_set_resid(sc, scsi_bufflen(sc));
if (conn->ctask == ctask)
conn->ctask = NULL;
/* release ref from queuecommand */
__iscsi_put_ctask(ctask);
}

/*
* Fail commands. session lock held and recv side suspended and xmit
* thread flushed
Expand Down Expand Up @@ -1837,22 +1859,13 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn)
/* handle pending */
list_for_each_entry_safe(mtask, tmp, &conn->mgmtqueue, running) {
debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt);
list_del_init(&mtask->running);
if (mtask == conn->login_mtask)
continue;
__kfifo_put(session->mgmtpool.queue, (void*)&mtask,
sizeof(void*));
iscsi_free_mgmt_task(conn, mtask);
}

/* handle running */
list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) {
debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt);
list_del_init(&mtask->running);

if (mtask == conn->login_mtask)
continue;
__kfifo_put(session->mgmtpool.queue, (void*)&mtask,
sizeof(void*));
iscsi_free_mgmt_task(conn, mtask);
}

conn->mtask = NULL;
Expand Down
2 changes: 2 additions & 0 deletions include/scsi/libiscsi.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,8 @@ extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
extern int iscsi_verify_itt(struct iscsi_conn *, struct iscsi_hdr *,
uint32_t *);
extern void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask);
extern void iscsi_free_mgmt_task(struct iscsi_conn *conn,
struct iscsi_mgmt_task *mtask);

/*
* generic helpers
Expand Down
1 change: 1 addition & 0 deletions include/scsi/scsi_transport_iscsi.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ struct iscsi_cls_conn {
#define ISCSI_STATE_TERMINATE 4
#define ISCSI_STATE_IN_RECOVERY 5
#define ISCSI_STATE_RECOVERY_FAILED 6
#define ISCSI_STATE_LOGGING_OUT 7

struct iscsi_cls_session {
struct list_head sess_list; /* item in session_list */
Expand Down

0 comments on commit b3a7ea8

Please sign in to comment.