aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2006-07-24 16:47:26 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-07-28 12:48:32 -0400
commit1c83469d36a9dd30dbf1fb9fc5ca3be3a0e64ff4 (patch)
treed20c53420f6596ebd6500562b294ef820a190887
parent7ea8b82847293c2311cf08fc3ed31ab0e452a27e (diff)
[SCSI] iscsi bugfixes: fix oops when iser is flushing io
When we enter recovery and flush the running commands we cannot freee the connection before flushing the commands. Some commands may have a reference to the connection that needs to be released before. iscsi_stop was forcing the term and suspend too early and was causing a oops in iser, so this patch removes those callbacks all together and allows the LLD to handle that detail. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c22
-rw-r--r--drivers/scsi/iscsi_tcp.c67
-rw-r--r--drivers/scsi/libiscsi.c12
-rw-r--r--include/scsi/scsi_transport_iscsi.h4
4 files changed, 34 insertions, 71 deletions
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 34b0da5cfa0a..1437d7ee3b19 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -378,21 +378,6 @@ iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn)
378 return iser_conn_set_full_featured_mode(conn); 378 return iser_conn_set_full_featured_mode(conn);
379} 379}
380 380
381static void
382iscsi_iser_conn_terminate(struct iscsi_conn *conn)
383{
384 struct iscsi_iser_conn *iser_conn = conn->dd_data;
385 struct iser_conn *ib_conn = iser_conn->ib_conn;
386
387 BUG_ON(!ib_conn);
388 /* starts conn teardown process, waits until all previously *
389 * posted buffers get flushed, deallocates all conn resources */
390 iser_conn_terminate(ib_conn);
391 iser_conn->ib_conn = NULL;
392 conn->recv_lock = NULL;
393}
394
395
396static struct iscsi_transport iscsi_iser_transport; 381static struct iscsi_transport iscsi_iser_transport;
397 382
398static struct iscsi_cls_session * 383static struct iscsi_cls_session *
@@ -555,13 +540,13 @@ iscsi_iser_ep_poll(__u64 ep_handle, int timeout_ms)
555static void 540static void
556iscsi_iser_ep_disconnect(__u64 ep_handle) 541iscsi_iser_ep_disconnect(__u64 ep_handle)
557{ 542{
558 struct iser_conn *ib_conn = iscsi_iser_ib_conn_lookup(ep_handle); 543 struct iser_conn *ib_conn;
559 544
545 ib_conn = iscsi_iser_ib_conn_lookup(ep_handle);
560 if (!ib_conn) 546 if (!ib_conn)
561 return; 547 return;
562 548
563 iser_err("ib conn %p state %d\n",ib_conn, ib_conn->state); 549 iser_err("ib conn %p state %d\n",ib_conn, ib_conn->state);
564
565 iser_conn_terminate(ib_conn); 550 iser_conn_terminate(ib_conn);
566} 551}
567 552
@@ -614,9 +599,6 @@ static struct iscsi_transport iscsi_iser_transport = {
614 .get_session_param = iscsi_session_get_param, 599 .get_session_param = iscsi_session_get_param,
615 .start_conn = iscsi_iser_conn_start, 600 .start_conn = iscsi_iser_conn_start,
616 .stop_conn = iscsi_conn_stop, 601 .stop_conn = iscsi_conn_stop,
617 /* these are called as part of conn recovery */
618 .suspend_conn_recv = NULL, /* FIXME is/how this relvant to iser? */
619 .terminate_conn = iscsi_iser_conn_terminate,
620 /* IO */ 602 /* IO */
621 .send_pdu = iscsi_conn_send_pdu, 603 .send_pdu = iscsi_conn_send_pdu,
622 .get_stats = iscsi_iser_conn_get_stats, 604 .get_stats = iscsi_iser_conn_get_stats,
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 7d784596a1ea..b6c68be6b866 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -1040,9 +1040,8 @@ iscsi_conn_set_callbacks(struct iscsi_conn *conn)
1040} 1040}
1041 1041
1042static void 1042static void
1043iscsi_conn_restore_callbacks(struct iscsi_conn *conn) 1043iscsi_conn_restore_callbacks(struct iscsi_tcp_conn *tcp_conn)
1044{ 1044{
1045 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
1046 struct sock *sk = tcp_conn->sock->sk; 1045 struct sock *sk = tcp_conn->sock->sk;
1047 1046
1048 /* restore socket callbacks, see also: iscsi_conn_set_callbacks() */ 1047 /* restore socket callbacks, see also: iscsi_conn_set_callbacks() */
@@ -1933,6 +1932,23 @@ tcp_conn_alloc_fail:
1933} 1932}
1934 1933
1935static void 1934static void
1935iscsi_tcp_release_conn(struct iscsi_conn *conn)
1936{
1937 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
1938
1939 if (!tcp_conn->sock)
1940 return;
1941
1942 sock_hold(tcp_conn->sock->sk);
1943 iscsi_conn_restore_callbacks(tcp_conn);
1944 sock_put(tcp_conn->sock->sk);
1945
1946 sock_release(tcp_conn->sock);
1947 tcp_conn->sock = NULL;
1948 conn->recv_lock = NULL;
1949}
1950
1951static void
1936iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn) 1952iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn)
1937{ 1953{
1938 struct iscsi_conn *conn = cls_conn->dd_data; 1954 struct iscsi_conn *conn = cls_conn->dd_data;
@@ -1942,6 +1958,7 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn)
1942 if (conn->hdrdgst_en || conn->datadgst_en) 1958 if (conn->hdrdgst_en || conn->datadgst_en)
1943 digest = 1; 1959 digest = 1;
1944 1960
1961 iscsi_tcp_release_conn(conn);
1945 iscsi_conn_teardown(cls_conn); 1962 iscsi_conn_teardown(cls_conn);
1946 1963
1947 /* now free tcp_conn */ 1964 /* now free tcp_conn */
@@ -1965,6 +1982,15 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn)
1965 kfree(tcp_conn); 1982 kfree(tcp_conn);
1966} 1983}
1967 1984
1985static void
1986iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
1987{
1988 struct iscsi_conn *conn = cls_conn->dd_data;
1989
1990 iscsi_conn_stop(cls_conn, flag);
1991 iscsi_tcp_release_conn(conn);
1992}
1993
1968static int 1994static int
1969iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, 1995iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
1970 struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, 1996 struct iscsi_cls_conn *cls_conn, uint64_t transport_eph,
@@ -2013,38 +2039,6 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
2013 return 0; 2039 return 0;
2014} 2040}
2015 2041
2016static void
2017iscsi_tcp_suspend_conn_rx(struct iscsi_conn *conn)
2018{
2019 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
2020 struct sock *sk;
2021
2022 if (!tcp_conn->sock)
2023 return;
2024
2025 sk = tcp_conn->sock->sk;
2026 write_lock_bh(&sk->sk_callback_lock);
2027 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
2028 write_unlock_bh(&sk->sk_callback_lock);
2029}
2030
2031static void
2032iscsi_tcp_terminate_conn(struct iscsi_conn *conn)
2033{
2034 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
2035
2036 if (!tcp_conn->sock)
2037 return;
2038
2039 sock_hold(tcp_conn->sock->sk);
2040 iscsi_conn_restore_callbacks(conn);
2041 sock_put(tcp_conn->sock->sk);
2042
2043 sock_release(tcp_conn->sock);
2044 tcp_conn->sock = NULL;
2045 conn->recv_lock = NULL;
2046}
2047
2048/* called with host lock */ 2042/* called with host lock */
2049static void 2043static void
2050iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask, 2044iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask,
@@ -2413,10 +2407,7 @@ static struct iscsi_transport iscsi_tcp_transport = {
2413 .get_conn_param = iscsi_tcp_conn_get_param, 2407 .get_conn_param = iscsi_tcp_conn_get_param,
2414 .get_session_param = iscsi_session_get_param, 2408 .get_session_param = iscsi_session_get_param,
2415 .start_conn = iscsi_conn_start, 2409 .start_conn = iscsi_conn_start,
2416 .stop_conn = iscsi_conn_stop, 2410 .stop_conn = iscsi_tcp_conn_stop,
2417 /* these are called as part of conn recovery */
2418 .suspend_conn_recv = iscsi_tcp_suspend_conn_rx,
2419 .terminate_conn = iscsi_tcp_terminate_conn,
2420 /* IO */ 2411 /* IO */
2421 .send_pdu = iscsi_conn_send_pdu, 2412 .send_pdu = iscsi_conn_send_pdu,
2422 .get_stats = iscsi_conn_get_stats, 2413 .get_stats = iscsi_conn_get_stats,
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 4e2ca8f7d9a1..36f520b9260e 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1440,12 +1440,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
1440 1440
1441 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 1441 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1442 mutex_lock(&conn->xmitmutex); 1442 mutex_lock(&conn->xmitmutex);
1443 if (conn->c_stage == ISCSI_CONN_INITIAL_STAGE) {
1444 if (session->tt->suspend_conn_recv)
1445 session->tt->suspend_conn_recv(conn);
1446
1447 session->tt->terminate_conn(conn);
1448 }
1449 1443
1450 spin_lock_bh(&session->lock); 1444 spin_lock_bh(&session->lock);
1451 conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; 1445 conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
@@ -1622,8 +1616,9 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
1622 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 1616 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1623 spin_unlock_bh(&session->lock); 1617 spin_unlock_bh(&session->lock);
1624 1618
1625 if (session->tt->suspend_conn_recv) 1619 write_lock_bh(conn->recv_lock);
1626 session->tt->suspend_conn_recv(conn); 1620 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
1621 write_unlock_bh(conn->recv_lock);
1627 1622
1628 mutex_lock(&conn->xmitmutex); 1623 mutex_lock(&conn->xmitmutex);
1629 /* 1624 /*
@@ -1642,7 +1637,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
1642 } 1637 }
1643 } 1638 }
1644 1639
1645 session->tt->terminate_conn(conn);
1646 /* 1640 /*
1647 * flush queues. 1641 * flush queues.
1648 */ 1642 */
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 5a3df1d7085f..39e833260bd0 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -57,8 +57,6 @@ struct sockaddr;
57 * @stop_conn: suspend/recover/terminate connection 57 * @stop_conn: suspend/recover/terminate connection
58 * @send_pdu: send iSCSI PDU, Login, Logout, NOP-Out, Reject, Text. 58 * @send_pdu: send iSCSI PDU, Login, Logout, NOP-Out, Reject, Text.
59 * @session_recovery_timedout: notify LLD a block during recovery timed out 59 * @session_recovery_timedout: notify LLD a block during recovery timed out
60 * @suspend_conn_recv: susepend the recv side of the connection
61 * @termincate_conn: destroy socket connection. Called with mutex lock.
62 * @init_cmd_task: Initialize a iscsi_cmd_task and any internal structs. 60 * @init_cmd_task: Initialize a iscsi_cmd_task and any internal structs.
63 * Called from queuecommand with session lock held. 61 * Called from queuecommand with session lock held.
64 * @init_mgmt_task: Initialize a iscsi_mgmt_task and any internal structs. 62 * @init_mgmt_task: Initialize a iscsi_mgmt_task and any internal structs.
@@ -112,8 +110,6 @@ struct iscsi_transport {
112 char *data, uint32_t data_size); 110 char *data, uint32_t data_size);
113 void (*get_stats) (struct iscsi_cls_conn *conn, 111 void (*get_stats) (struct iscsi_cls_conn *conn,
114 struct iscsi_stats *stats); 112 struct iscsi_stats *stats);
115 void (*suspend_conn_recv) (struct iscsi_conn *conn);
116 void (*terminate_conn) (struct iscsi_conn *conn);
117 void (*init_cmd_task) (struct iscsi_cmd_task *ctask); 113 void (*init_cmd_task) (struct iscsi_cmd_task *ctask);
118 void (*init_mgmt_task) (struct iscsi_conn *conn, 114 void (*init_mgmt_task) (struct iscsi_conn *conn,
119 struct iscsi_mgmt_task *mtask, 115 struct iscsi_mgmt_task *mtask,