Skip to content

Commit

Permalink
libiscsi: don't run scsi eh if iscsi task is making progress
Browse files Browse the repository at this point in the history
If we are sending or receiving data for the task successfully do
not run the scsi eh, because we know the task is making progress.

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 Jun 21, 2009
1 parent 9194c62 commit d355e57
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 15 deletions.
62 changes: 49 additions & 13 deletions drivers/scsi/libiscsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
task = iscsi_itt_to_ctask(conn, hdr->itt);
if (!task)
return ISCSI_ERR_BAD_ITT;
task->last_xfer = jiffies;
break;
case ISCSI_OP_R2T:
/*
Expand Down Expand Up @@ -1192,10 +1193,12 @@ static int iscsi_xmit_task(struct iscsi_conn *conn)
spin_unlock_bh(&conn->session->lock);
rc = conn->session->tt->xmit_task(task);
spin_lock_bh(&conn->session->lock);
__iscsi_put_task(task);
if (!rc)
if (!rc) {
/* done with this task */
task->last_xfer = jiffies;
conn->task = NULL;
}
__iscsi_put_task(task);
return rc;
}

Expand Down Expand Up @@ -1361,6 +1364,9 @@ static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
task->state = ISCSI_TASK_PENDING;
task->conn = conn;
task->sc = sc;
task->have_checked_conn = false;
task->last_timeout = jiffies;
task->last_xfer = jiffies;
INIT_LIST_HEAD(&task->running);
return task;
}
Expand Down Expand Up @@ -1716,17 +1722,18 @@ static int iscsi_has_ping_timed_out(struct iscsi_conn *conn)
return 0;
}

static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
{
enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;
struct iscsi_task *task = NULL;
struct iscsi_cls_session *cls_session;
struct iscsi_session *session;
struct iscsi_conn *conn;
enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;

cls_session = starget_to_session(scsi_target(scmd->device));
cls_session = starget_to_session(scsi_target(sc->device));
session = cls_session->dd_data;

ISCSI_DBG_SESSION(session, "scsi cmd %p timedout\n", scmd);
ISCSI_DBG_SESSION(session, "scsi cmd %p timedout\n", sc);

spin_lock(&session->lock);
if (session->state != ISCSI_STATE_LOGGED_IN) {
Expand All @@ -1745,6 +1752,26 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
goto done;
}

task = (struct iscsi_task *)sc->SCp.ptr;
if (!task)
goto done;
/*
* If we have sent (at least queued to the network layer) a pdu or
* recvd one for the task since the last timeout ask for
* more time. If on the next timeout we have not made progress
* we can check if it is the task or connection when we send the
* nop as a ping.
*/
if (time_after_eq(task->last_xfer, task->last_timeout)) {
ISCSI_DBG_CONN(conn, "Command making progress. Asking "
"scsi-ml for more time to complete. "
"Last data recv at %lu. Last timeout was at "
"%lu\n.", task->last_xfer, task->last_timeout);
task->have_checked_conn = false;
rc = BLK_EH_RESET_TIMER;
goto done;
}

if (!conn->recv_timeout && !conn->ping_timeout)
goto done;
/*
Expand All @@ -1755,20 +1782,29 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
rc = BLK_EH_RESET_TIMER;
goto done;
}

/* Assumes nop timeout is shorter than scsi cmd timeout */
if (task->have_checked_conn)
goto done;

/*
* if we are about to check the transport then give the command
* more time
* Checking the transport already or nop from a cmd timeout still
* running
*/
if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ),
jiffies)) {
if (conn->ping_task) {
task->have_checked_conn = true;
rc = BLK_EH_RESET_TIMER;
goto done;
}

/* if in the middle of checking the transport then give us more time */
if (conn->ping_task)
rc = BLK_EH_RESET_TIMER;
/* Make sure there is a transport check done */
iscsi_send_nopout(conn, NULL);
task->have_checked_conn = true;
rc = BLK_EH_RESET_TIMER;

done:
if (task)
task->last_timeout = jiffies;
spin_unlock(&session->lock);
ISCSI_DBG_SESSION(session, "return %s\n", rc == BLK_EH_RESET_TIMER ?
"timer reset" : "nh");
Expand Down
6 changes: 4 additions & 2 deletions drivers/scsi/libiscsi_tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
"offset=%d, datalen=%d)\n",
tcp_task->data_offset,
tcp_conn->in.datalen);
task->last_xfer = jiffies;
rc = iscsi_segment_seek_sg(&tcp_conn->in.segment,
sdb->table.sgl,
sdb->table.nents,
Expand Down Expand Up @@ -713,9 +714,10 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
rc = ISCSI_ERR_BAD_ITT;
else if (ahslen)
rc = ISCSI_ERR_AHSLEN;
else if (task->sc->sc_data_direction == DMA_TO_DEVICE)
else if (task->sc->sc_data_direction == DMA_TO_DEVICE) {
task->last_xfer = jiffies;
rc = iscsi_tcp_r2t_rsp(conn, task);
else
} else
rc = ISCSI_ERR_PROTO;
spin_unlock(&conn->session->lock);
break;
Expand Down
4 changes: 4 additions & 0 deletions include/scsi/libiscsi.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ struct iscsi_task {
struct scsi_cmnd *sc; /* associated SCSI cmd*/
struct iscsi_conn *conn; /* used connection */

/* data processing tracking */
unsigned long last_xfer;
unsigned long last_timeout;
bool have_checked_conn;
/* state set/tested under session->lock */
int state;
atomic_t refcount;
Expand Down

0 comments on commit d355e57

Please sign in to comment.