From 77a23c21aaa723f6b0ffc4a701be8c8e5a32346d Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:18 -0500 Subject: [SCSI] libiscsi: fix iscsi cmdsn allocation The cmdsn allocation and pdu transmit code can race, and we can end up sending a pdu with cmdsn 10 before a pdu with 5. The target will then fail the connection/session. This patch fixes the problem by delaying the cmdsn allocation until we are about to send the pdu. This also removes the xmitmutex. We were using the connection xmitmutex during error handling to handle races with mtask and ctask cleanup and completion. For ctasks we now have nice refcounting and for the mtask, if we hit the case where the mtask timesout and it is floating around somewhere in the driver, we end up dropping the session. And to handle session level cleanup, we use the xmit suspend bit along with scsi_flush_queue and the session lock to make sure that the xmit thread is not possibly transmitting a task while we are trying to kill it. Signed-off-by: Mike Christie Cc: Roland Dreier Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 0afdca2224c2..8edcfddc0baf 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -211,7 +210,6 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) static int iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) { - int rc; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr; @@ -219,9 +217,7 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) struct scsi_cmnd *sc = ctask->sc; int datasn = be32_to_cpu(rhdr->datasn); - rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr); - if (rc) - return rc; + iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); /* * setup Data-In byte counter (gets decremented..) */ @@ -377,12 +373,10 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) return ISCSI_ERR_R2TSN; } - rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr); - if (rc) - return rc; - /* fill-in new R2T associated with the task */ spin_lock(&session->lock); + iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); + if (!ctask->sc || ctask->mtask || session->state != ISCSI_STATE_LOGGED_IN) { printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in " @@ -1762,12 +1756,6 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) debug_scsi("ctask deq [cid %d xmstate %x itt 0x%x]\n", conn->id, tcp_ctask->xmstate, ctask->itt); - /* - * serialize with TMF AbortTask - */ - if (ctask->mtask) - return rc; - rc = iscsi_send_cmd_hdr(conn, ctask); if (rc) return rc; @@ -1949,8 +1937,7 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, /* called with host lock */ static void -iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask, - char *data, uint32_t data_size) +iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) { struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data; tcp_mtask->xmstate = XMSTATE_IMM_HDR_INIT; @@ -2073,22 +2060,15 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, switch(param) { case ISCSI_PARAM_CONN_PORT: - mutex_lock(&conn->xmitmutex); - if (!tcp_conn->sock) { - mutex_unlock(&conn->xmitmutex); + if (!tcp_conn->sock) return -EINVAL; - } inet = inet_sk(tcp_conn->sock->sk); len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport)); - mutex_unlock(&conn->xmitmutex); break; case ISCSI_PARAM_CONN_ADDRESS: - mutex_lock(&conn->xmitmutex); - if (!tcp_conn->sock) { - mutex_unlock(&conn->xmitmutex); + if (!tcp_conn->sock) return -EINVAL; - } sk = tcp_conn->sock->sk; if (sk->sk_family == PF_INET) { @@ -2099,7 +2079,6 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, np = inet6_sk(sk); len = sprintf(buf, NIP6_FMT "\n", NIP6(np->daddr)); } - mutex_unlock(&conn->xmitmutex); break; default: return iscsi_conn_get_param(cls_conn, param, buf); -- cgit v1.2.1