aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2013-07-03 06:05:37 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-08-04 04:50:33 -0400
commitd9e507c05ca19ad2ec166577edd8b47e17c8961e (patch)
treea3369adbf8ab02bc88eca6549c5ad4bc4a12b21e
parenta5d56a2217664c7bc06cb7deeac9a2a155ba4345 (diff)
iser-target: Fix session reset bug with RDMA_CM_EVENT_DISCONNECTED
commit b2cb96494d83b894a43ba8b9023eead8ff50684b upstream. This patch addresses a bug where RDMA_CM_EVENT_DISCONNECTED may occur before the connection shutdown has been completed by rx/tx threads, that causes isert_free_conn() to wait indefinately on ->conn_wait. This patch allows isert_disconnect_work code to invoke rdma_disconnect when isert_disconnect_work() process context is started by client session reset before isert_free_conn() code has been reached. It also adds isert_conn->conn_mutex protection for ->state within isert_disconnect_work(), isert_cq_comp_err() and isert_free_conn() code, along with isert_check_state() for wait_event usage. (v2: Add explicit iscsit_cause_connection_reinstatement call during isert_disconnect_work() to force conn reset) Cc: Or Gerlitz <ogerlitz@mellanox.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c70
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.h1
-rw-r--r--drivers/target/iscsi/iscsi_target_erl0.c1
-rw-r--r--include/target/iscsi/iscsi_transport.h4
4 files changed, 66 insertions, 10 deletions
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index 6559febd255e..6b20a9d09cbb 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -388,6 +388,7 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
388 init_waitqueue_head(&isert_conn->conn_wait_comp_err); 388 init_waitqueue_head(&isert_conn->conn_wait_comp_err);
389 kref_init(&isert_conn->conn_kref); 389 kref_init(&isert_conn->conn_kref);
390 kref_get(&isert_conn->conn_kref); 390 kref_get(&isert_conn->conn_kref);
391 mutex_init(&isert_conn->conn_mutex);
391 392
392 cma_id->context = isert_conn; 393 cma_id->context = isert_conn;
393 isert_conn->conn_cm_id = cma_id; 394 isert_conn->conn_cm_id = cma_id;
@@ -540,15 +541,32 @@ isert_disconnect_work(struct work_struct *work)
540 struct isert_conn, conn_logout_work); 541 struct isert_conn, conn_logout_work);
541 542
542 pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); 543 pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
543 544 mutex_lock(&isert_conn->conn_mutex);
544 isert_conn->state = ISER_CONN_DOWN; 545 isert_conn->state = ISER_CONN_DOWN;
545 546
546 if (isert_conn->post_recv_buf_count == 0 && 547 if (isert_conn->post_recv_buf_count == 0 &&
547 atomic_read(&isert_conn->post_send_buf_count) == 0) { 548 atomic_read(&isert_conn->post_send_buf_count) == 0) {
548 pr_debug("Calling wake_up(&isert_conn->conn_wait);\n"); 549 pr_debug("Calling wake_up(&isert_conn->conn_wait);\n");
549 wake_up(&isert_conn->conn_wait); 550 mutex_unlock(&isert_conn->conn_mutex);
551 goto wake_up;
552 }
553 if (!isert_conn->conn_cm_id) {
554 mutex_unlock(&isert_conn->conn_mutex);
555 isert_put_conn(isert_conn);
556 return;
557 }
558 if (!isert_conn->logout_posted) {
559 pr_debug("Calling rdma_disconnect for !logout_posted from"
560 " isert_disconnect_work\n");
561 rdma_disconnect(isert_conn->conn_cm_id);
562 mutex_unlock(&isert_conn->conn_mutex);
563 iscsit_cause_connection_reinstatement(isert_conn->conn, 0);
564 goto wake_up;
550 } 565 }
566 mutex_unlock(&isert_conn->conn_mutex);
551 567
568wake_up:
569 wake_up(&isert_conn->conn_wait);
552 isert_put_conn(isert_conn); 570 isert_put_conn(isert_conn);
553} 571}
554 572
@@ -1423,7 +1441,11 @@ isert_cq_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
1423 pr_debug("isert_cq_comp_err >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); 1441 pr_debug("isert_cq_comp_err >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1424 pr_debug("Calling wake_up from isert_cq_comp_err\n"); 1442 pr_debug("Calling wake_up from isert_cq_comp_err\n");
1425 1443
1426 isert_conn->state = ISER_CONN_TERMINATING; 1444 mutex_lock(&isert_conn->conn_mutex);
1445 if (isert_conn->state != ISER_CONN_DOWN)
1446 isert_conn->state = ISER_CONN_TERMINATING;
1447 mutex_unlock(&isert_conn->conn_mutex);
1448
1427 wake_up(&isert_conn->conn_wait_comp_err); 1449 wake_up(&isert_conn->conn_wait_comp_err);
1428 } 1450 }
1429} 1451}
@@ -2193,6 +2215,17 @@ isert_free_np(struct iscsi_np *np)
2193 kfree(isert_np); 2215 kfree(isert_np);
2194} 2216}
2195 2217
2218static int isert_check_state(struct isert_conn *isert_conn, int state)
2219{
2220 int ret;
2221
2222 mutex_lock(&isert_conn->conn_mutex);
2223 ret = (isert_conn->state == state);
2224 mutex_unlock(&isert_conn->conn_mutex);
2225
2226 return ret;
2227}
2228
2196static void isert_free_conn(struct iscsi_conn *conn) 2229static void isert_free_conn(struct iscsi_conn *conn)
2197{ 2230{
2198 struct isert_conn *isert_conn = conn->context; 2231 struct isert_conn *isert_conn = conn->context;
@@ -2202,26 +2235,43 @@ static void isert_free_conn(struct iscsi_conn *conn)
2202 * Decrement post_send_buf_count for special case when called 2235 * Decrement post_send_buf_count for special case when called
2203 * from isert_do_control_comp() -> iscsit_logout_post_handler() 2236 * from isert_do_control_comp() -> iscsit_logout_post_handler()
2204 */ 2237 */
2238 mutex_lock(&isert_conn->conn_mutex);
2205 if (isert_conn->logout_posted) 2239 if (isert_conn->logout_posted)
2206 atomic_dec(&isert_conn->post_send_buf_count); 2240 atomic_dec(&isert_conn->post_send_buf_count);
2207 2241
2208 if (isert_conn->conn_cm_id) 2242 if (isert_conn->conn_cm_id && isert_conn->state != ISER_CONN_DOWN) {
2243 pr_debug("Calling rdma_disconnect from isert_free_conn\n");
2209 rdma_disconnect(isert_conn->conn_cm_id); 2244 rdma_disconnect(isert_conn->conn_cm_id);
2245 }
2210 /* 2246 /*
2211 * Only wait for conn_wait_comp_err if the isert_conn made it 2247 * Only wait for conn_wait_comp_err if the isert_conn made it
2212 * into full feature phase.. 2248 * into full feature phase..
2213 */ 2249 */
2214 if (isert_conn->state > ISER_CONN_INIT) { 2250 if (isert_conn->state == ISER_CONN_UP) {
2215 pr_debug("isert_free_conn: Before wait_event comp_err %d\n", 2251 pr_debug("isert_free_conn: Before wait_event comp_err %d\n",
2216 isert_conn->state); 2252 isert_conn->state);
2253 mutex_unlock(&isert_conn->conn_mutex);
2254
2217 wait_event(isert_conn->conn_wait_comp_err, 2255 wait_event(isert_conn->conn_wait_comp_err,
2218 isert_conn->state == ISER_CONN_TERMINATING); 2256 (isert_check_state(isert_conn, ISER_CONN_TERMINATING)));
2219 pr_debug("isert_free_conn: After wait_event #1 >>>>>>>>>>>>\n"); 2257
2258 wait_event(isert_conn->conn_wait,
2259 (isert_check_state(isert_conn, ISER_CONN_DOWN)));
2260
2261 isert_put_conn(isert_conn);
2262 return;
2263 }
2264 if (isert_conn->state == ISER_CONN_INIT) {
2265 mutex_unlock(&isert_conn->conn_mutex);
2266 isert_put_conn(isert_conn);
2267 return;
2220 } 2268 }
2269 pr_debug("isert_free_conn: wait_event conn_wait %d\n",
2270 isert_conn->state);
2271 mutex_unlock(&isert_conn->conn_mutex);
2221 2272
2222 pr_debug("isert_free_conn: wait_event conn_wait %d\n", isert_conn->state); 2273 wait_event(isert_conn->conn_wait,
2223 wait_event(isert_conn->conn_wait, isert_conn->state == ISER_CONN_DOWN); 2274 (isert_check_state(isert_conn, ISER_CONN_DOWN)));
2224 pr_debug("isert_free_conn: After wait_event #2 >>>>>>>>>>>>>>>>>>>>\n");
2225 2275
2226 isert_put_conn(isert_conn); 2276 isert_put_conn(isert_conn);
2227} 2277}
diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h
index b104f4c2cd38..5795c82a2306 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.h
+++ b/drivers/infiniband/ulp/isert/ib_isert.h
@@ -102,6 +102,7 @@ struct isert_conn {
102 struct ib_qp *conn_qp; 102 struct ib_qp *conn_qp;
103 struct isert_device *conn_device; 103 struct isert_device *conn_device;
104 struct work_struct conn_logout_work; 104 struct work_struct conn_logout_work;
105 struct mutex conn_mutex;
105 wait_queue_head_t conn_wait; 106 wait_queue_head_t conn_wait;
106 wait_queue_head_t conn_wait_comp_err; 107 wait_queue_head_t conn_wait_comp_err;
107 struct kref conn_kref; 108 struct kref conn_kref;
diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c
index dcb199da06b9..7f1116635d17 100644
--- a/drivers/target/iscsi/iscsi_target_erl0.c
+++ b/drivers/target/iscsi/iscsi_target_erl0.c
@@ -909,6 +909,7 @@ void iscsit_cause_connection_reinstatement(struct iscsi_conn *conn, int sleep)
909 wait_for_completion(&conn->conn_wait_comp); 909 wait_for_completion(&conn->conn_wait_comp);
910 complete(&conn->conn_post_wait_comp); 910 complete(&conn->conn_post_wait_comp);
911} 911}
912EXPORT_SYMBOL(iscsit_cause_connection_reinstatement);
912 913
913void iscsit_fall_back_to_erl0(struct iscsi_session *sess) 914void iscsit_fall_back_to_erl0(struct iscsi_session *sess)
914{ 915{
diff --git a/include/target/iscsi/iscsi_transport.h b/include/target/iscsi/iscsi_transport.h
index 23a87d0cd72c..6db632eb3821 100644
--- a/include/target/iscsi/iscsi_transport.h
+++ b/include/target/iscsi/iscsi_transport.h
@@ -67,6 +67,10 @@ extern int iscsit_logout_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
67 */ 67 */
68extern void iscsit_increment_maxcmdsn(struct iscsi_cmd *, struct iscsi_session *); 68extern void iscsit_increment_maxcmdsn(struct iscsi_cmd *, struct iscsi_session *);
69/* 69/*
70 * From iscsi_target_erl0.c
71 */
72extern void iscsit_cause_connection_reinstatement(struct iscsi_conn *, int);
73/*
70 * From iscsi_target_erl1.c 74 * From iscsi_target_erl1.c
71 */ 75 */
72extern void iscsit_stop_dataout_timer(struct iscsi_cmd *); 76extern void iscsit_stop_dataout_timer(struct iscsi_cmd *);