aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/iscsi_tcp.c
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2007-05-30 13:57:18 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-06-02 15:34:14 -0400
commit77a23c21aaa723f6b0ffc4a701be8c8e5a32346d (patch)
tree5b51b8299a8deede4c91dffde032899ab76e331a /drivers/scsi/iscsi_tcp.c
parent218432c68085d6c2b04df57daaf105d2ffa2aa61 (diff)
[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 <michaelc@cs.wisc.edu> Cc: Roland Dreier <rdreier@cisco.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/iscsi_tcp.c')
-rw-r--r--drivers/scsi/iscsi_tcp.c33
1 files changed, 6 insertions, 27 deletions
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 @@
34#include <linux/delay.h> 34#include <linux/delay.h>
35#include <linux/kfifo.h> 35#include <linux/kfifo.h>
36#include <linux/scatterlist.h> 36#include <linux/scatterlist.h>
37#include <linux/mutex.h>
38#include <net/tcp.h> 37#include <net/tcp.h>
39#include <scsi/scsi_cmnd.h> 38#include <scsi/scsi_cmnd.h>
40#include <scsi/scsi_host.h> 39#include <scsi/scsi_host.h>
@@ -211,7 +210,6 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
211static int 210static int
212iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) 211iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
213{ 212{
214 int rc;
215 struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 213 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
216 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; 214 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
217 struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr; 215 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)
219 struct scsi_cmnd *sc = ctask->sc; 217 struct scsi_cmnd *sc = ctask->sc;
220 int datasn = be32_to_cpu(rhdr->datasn); 218 int datasn = be32_to_cpu(rhdr->datasn);
221 219
222 rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr); 220 iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
223 if (rc)
224 return rc;
225 /* 221 /*
226 * setup Data-In byte counter (gets decremented..) 222 * setup Data-In byte counter (gets decremented..)
227 */ 223 */
@@ -377,12 +373,10 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
377 return ISCSI_ERR_R2TSN; 373 return ISCSI_ERR_R2TSN;
378 } 374 }
379 375
380 rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr);
381 if (rc)
382 return rc;
383
384 /* fill-in new R2T associated with the task */ 376 /* fill-in new R2T associated with the task */
385 spin_lock(&session->lock); 377 spin_lock(&session->lock);
378 iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
379
386 if (!ctask->sc || ctask->mtask || 380 if (!ctask->sc || ctask->mtask ||
387 session->state != ISCSI_STATE_LOGGED_IN) { 381 session->state != ISCSI_STATE_LOGGED_IN) {
388 printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in " 382 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)
1762 debug_scsi("ctask deq [cid %d xmstate %x itt 0x%x]\n", 1756 debug_scsi("ctask deq [cid %d xmstate %x itt 0x%x]\n",
1763 conn->id, tcp_ctask->xmstate, ctask->itt); 1757 conn->id, tcp_ctask->xmstate, ctask->itt);
1764 1758
1765 /*
1766 * serialize with TMF AbortTask
1767 */
1768 if (ctask->mtask)
1769 return rc;
1770
1771 rc = iscsi_send_cmd_hdr(conn, ctask); 1759 rc = iscsi_send_cmd_hdr(conn, ctask);
1772 if (rc) 1760 if (rc)
1773 return rc; 1761 return rc;
@@ -1949,8 +1937,7 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
1949 1937
1950/* called with host lock */ 1938/* called with host lock */
1951static void 1939static void
1952iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask, 1940iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
1953 char *data, uint32_t data_size)
1954{ 1941{
1955 struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data; 1942 struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
1956 tcp_mtask->xmstate = XMSTATE_IMM_HDR_INIT; 1943 tcp_mtask->xmstate = XMSTATE_IMM_HDR_INIT;
@@ -2073,22 +2060,15 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
2073 2060
2074 switch(param) { 2061 switch(param) {
2075 case ISCSI_PARAM_CONN_PORT: 2062 case ISCSI_PARAM_CONN_PORT:
2076 mutex_lock(&conn->xmitmutex); 2063 if (!tcp_conn->sock)
2077 if (!tcp_conn->sock) {
2078 mutex_unlock(&conn->xmitmutex);
2079 return -EINVAL; 2064 return -EINVAL;
2080 }
2081 2065
2082 inet = inet_sk(tcp_conn->sock->sk); 2066 inet = inet_sk(tcp_conn->sock->sk);
2083 len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport)); 2067 len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport));
2084 mutex_unlock(&conn->xmitmutex);
2085 break; 2068 break;
2086 case ISCSI_PARAM_CONN_ADDRESS: 2069 case ISCSI_PARAM_CONN_ADDRESS:
2087 mutex_lock(&conn->xmitmutex); 2070 if (!tcp_conn->sock)
2088 if (!tcp_conn->sock) {
2089 mutex_unlock(&conn->xmitmutex);
2090 return -EINVAL; 2071 return -EINVAL;
2091 }
2092 2072
2093 sk = tcp_conn->sock->sk; 2073 sk = tcp_conn->sock->sk;
2094 if (sk->sk_family == PF_INET) { 2074 if (sk->sk_family == PF_INET) {
@@ -2099,7 +2079,6 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
2099 np = inet6_sk(sk); 2079 np = inet6_sk(sk);
2100 len = sprintf(buf, NIP6_FMT "\n", NIP6(np->daddr)); 2080 len = sprintf(buf, NIP6_FMT "\n", NIP6(np->daddr));
2101 } 2081 }
2102 mutex_unlock(&conn->xmitmutex);
2103 break; 2082 break;
2104 default: 2083 default:
2105 return iscsi_conn_get_param(cls_conn, param, buf); 2084 return iscsi_conn_get_param(cls_conn, param, buf);