aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenny Derzhavetz <jennyf@mellanox.com>2015-09-06 07:52:24 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2015-09-15 18:47:27 -0400
commitbd3792205aaeb79b994338af2e5499fa503d79c7 (patch)
tree4a980e86962a6cbab80a53c95efa250721cc233c
parented8cb0a4378c0e7035db047987fe0e7309020ab5 (diff)
iser-target: Fix pending connections handling in target stack shutdown sequnce
Instead of handing a connection to the iscsi stack for processing right after accepting (rdma_accept) we only hand the connection to the iscsi core after we reached to a connected state (ESTABLISHED CM event). This will prevent two error scenrios: 1. race between rdma connection teardown and iscsi login sequence reported by Nic in: (ce9a9fc20a78a "iser-target: Fix REJECT CM event use-after-free OOPs") 2. target stack shutdown sequence race with constant login attempts by multiple initiators. We address this by maintaining two queues at the isert_np level: - accepted: connections that were accepted but have not reached connected state (might get rejected, unreachable or error). - pending: connections in connected state, but have yet to handed to the iscsi core for login processing. iser connections are promoted to the pending queue only from the accepted queue. This way the iscsi core now will only handle functional iser connections and once we shutdown the target stack, we look for any stales that got left behind so we can safely release them. Signed-off-by: Jenny Derzhavetz <jennyf@mellanox.com> Signed-off-by: Sagi Grimberg <sagig@mellanox.com> Cc: <stable@vger.kernel.org> # v3.10+ Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c66
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.h5
2 files changed, 40 insertions, 31 deletions
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index b163ec0ba2eb..f3f498f6ecc5 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -634,7 +634,7 @@ static void
634isert_init_conn(struct isert_conn *isert_conn) 634isert_init_conn(struct isert_conn *isert_conn)
635{ 635{
636 isert_conn->state = ISER_CONN_INIT; 636 isert_conn->state = ISER_CONN_INIT;
637 INIT_LIST_HEAD(&isert_conn->accept_node); 637 INIT_LIST_HEAD(&isert_conn->node);
638 init_completion(&isert_conn->login_comp); 638 init_completion(&isert_conn->login_comp);
639 init_completion(&isert_conn->login_req_comp); 639 init_completion(&isert_conn->login_req_comp);
640 init_completion(&isert_conn->wait); 640 init_completion(&isert_conn->wait);
@@ -762,28 +762,15 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
762 ret = isert_rdma_post_recvl(isert_conn); 762 ret = isert_rdma_post_recvl(isert_conn);
763 if (ret) 763 if (ret)
764 goto out_conn_dev; 764 goto out_conn_dev;
765 /*
766 * Obtain the second reference now before isert_rdma_accept() to
767 * ensure that any initiator generated REJECT CM event that occurs
768 * asynchronously won't drop the last reference until the error path
769 * in iscsi_target_login_sess_out() does it's ->iscsit_free_conn() ->
770 * isert_free_conn() -> isert_put_conn() -> kref_put().
771 */
772 if (!kref_get_unless_zero(&isert_conn->kref)) {
773 isert_warn("conn %p connect_release is running\n", isert_conn);
774 goto out_conn_dev;
775 }
776 765
777 ret = isert_rdma_accept(isert_conn); 766 ret = isert_rdma_accept(isert_conn);
778 if (ret) 767 if (ret)
779 goto out_conn_dev; 768 goto out_conn_dev;
780 769
781 mutex_lock(&isert_np->mutex); 770 mutex_lock(&isert_np->mutex);
782 list_add_tail(&isert_conn->accept_node, &isert_np->accept_list); 771 list_add_tail(&isert_conn->node, &isert_np->accepted);
783 mutex_unlock(&isert_np->mutex); 772 mutex_unlock(&isert_np->mutex);
784 773
785 isert_info("np %p: Allow accept_np to continue\n", np);
786 up(&isert_np->sem);
787 return 0; 774 return 0;
788 775
789out_conn_dev: 776out_conn_dev:
@@ -831,13 +818,21 @@ static void
831isert_connected_handler(struct rdma_cm_id *cma_id) 818isert_connected_handler(struct rdma_cm_id *cma_id)
832{ 819{
833 struct isert_conn *isert_conn = cma_id->qp->qp_context; 820 struct isert_conn *isert_conn = cma_id->qp->qp_context;
821 struct isert_np *isert_np = cma_id->context;
834 822
835 isert_info("conn %p\n", isert_conn); 823 isert_info("conn %p\n", isert_conn);
836 824
837 mutex_lock(&isert_conn->mutex); 825 mutex_lock(&isert_conn->mutex);
838 if (isert_conn->state != ISER_CONN_FULL_FEATURE) 826 isert_conn->state = ISER_CONN_UP;
839 isert_conn->state = ISER_CONN_UP; 827 kref_get(&isert_conn->kref);
840 mutex_unlock(&isert_conn->mutex); 828 mutex_unlock(&isert_conn->mutex);
829
830 mutex_lock(&isert_np->mutex);
831 list_move_tail(&isert_conn->node, &isert_np->pending);
832 mutex_unlock(&isert_np->mutex);
833
834 isert_info("np %p: Allow accept_np to continue\n", isert_np);
835 up(&isert_np->sem);
841} 836}
842 837
843static void 838static void
@@ -946,8 +941,8 @@ isert_disconnected_handler(struct rdma_cm_id *cma_id,
946 goto out; 941 goto out;
947 942
948 mutex_lock(&isert_np->mutex); 943 mutex_lock(&isert_np->mutex);
949 if (!list_empty(&isert_conn->accept_node)) { 944 if (!list_empty(&isert_conn->node)) {
950 list_del_init(&isert_conn->accept_node); 945 list_del_init(&isert_conn->node);
951 isert_put_conn(isert_conn); 946 isert_put_conn(isert_conn);
952 queue_work(isert_release_wq, &isert_conn->release_work); 947 queue_work(isert_release_wq, &isert_conn->release_work);
953 } 948 }
@@ -962,6 +957,7 @@ isert_connect_error(struct rdma_cm_id *cma_id)
962{ 957{
963 struct isert_conn *isert_conn = cma_id->qp->qp_context; 958 struct isert_conn *isert_conn = cma_id->qp->qp_context;
964 959
960 list_del_init(&isert_conn->node);
965 isert_conn->cm_id = NULL; 961 isert_conn->cm_id = NULL;
966 isert_put_conn(isert_conn); 962 isert_put_conn(isert_conn);
967 963
@@ -3115,7 +3111,8 @@ isert_setup_np(struct iscsi_np *np,
3115 } 3111 }
3116 sema_init(&isert_np->sem, 0); 3112 sema_init(&isert_np->sem, 0);
3117 mutex_init(&isert_np->mutex); 3113 mutex_init(&isert_np->mutex);
3118 INIT_LIST_HEAD(&isert_np->accept_list); 3114 INIT_LIST_HEAD(&isert_np->accepted);
3115 INIT_LIST_HEAD(&isert_np->pending);
3119 isert_np->np = np; 3116 isert_np->np = np;
3120 3117
3121 /* 3118 /*
@@ -3238,13 +3235,13 @@ accept_wait:
3238 spin_unlock_bh(&np->np_thread_lock); 3235 spin_unlock_bh(&np->np_thread_lock);
3239 3236
3240 mutex_lock(&isert_np->mutex); 3237 mutex_lock(&isert_np->mutex);
3241 if (list_empty(&isert_np->accept_list)) { 3238 if (list_empty(&isert_np->pending)) {
3242 mutex_unlock(&isert_np->mutex); 3239 mutex_unlock(&isert_np->mutex);
3243 goto accept_wait; 3240 goto accept_wait;
3244 } 3241 }
3245 isert_conn = list_first_entry(&isert_np->accept_list, 3242 isert_conn = list_first_entry(&isert_np->pending,
3246 struct isert_conn, accept_node); 3243 struct isert_conn, node);
3247 list_del_init(&isert_conn->accept_node); 3244 list_del_init(&isert_conn->node);
3248 mutex_unlock(&isert_np->mutex); 3245 mutex_unlock(&isert_np->mutex);
3249 3246
3250 conn->context = isert_conn; 3247 conn->context = isert_conn;
@@ -3271,14 +3268,25 @@ isert_free_np(struct iscsi_np *np)
3271 * that at this point we don't have hanging connections that 3268 * that at this point we don't have hanging connections that
3272 * completed RDMA establishment but didn't start iscsi login 3269 * completed RDMA establishment but didn't start iscsi login
3273 * process. So work-around this by cleaning up what ever piled 3270 * process. So work-around this by cleaning up what ever piled
3274 * up in accept_list. 3271 * up in accepted and pending lists.
3275 */ 3272 */
3276 mutex_lock(&isert_np->mutex); 3273 mutex_lock(&isert_np->mutex);
3277 if (!list_empty(&isert_np->accept_list)) { 3274 if (!list_empty(&isert_np->pending)) {
3278 isert_info("Still have isert connections, cleaning up...\n"); 3275 isert_info("Still have isert pending connections\n");
3276 list_for_each_entry_safe(isert_conn, n,
3277 &isert_np->pending,
3278 node) {
3279 isert_info("cleaning isert_conn %p state (%d)\n",
3280 isert_conn, isert_conn->state);
3281 isert_connect_release(isert_conn);
3282 }
3283 }
3284
3285 if (!list_empty(&isert_np->accepted)) {
3286 isert_info("Still have isert accepted connections\n");
3279 list_for_each_entry_safe(isert_conn, n, 3287 list_for_each_entry_safe(isert_conn, n,
3280 &isert_np->accept_list, 3288 &isert_np->accepted,
3281 accept_node) { 3289 node) {
3282 isert_info("cleaning isert_conn %p state (%d)\n", 3290 isert_info("cleaning isert_conn %p state (%d)\n",
3283 isert_conn, isert_conn->state); 3291 isert_conn, isert_conn->state);
3284 isert_connect_release(isert_conn); 3292 isert_connect_release(isert_conn);
diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h
index 6e85da3dd835..b81dfe07ce62 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.h
+++ b/drivers/infiniband/ulp/isert/ib_isert.h
@@ -159,7 +159,7 @@ struct isert_conn {
159 struct iser_rx_desc *rx_descs; 159 struct iser_rx_desc *rx_descs;
160 struct ib_recv_wr rx_wr[ISERT_MIN_POSTED_RX]; 160 struct ib_recv_wr rx_wr[ISERT_MIN_POSTED_RX];
161 struct iscsi_conn *conn; 161 struct iscsi_conn *conn;
162 struct list_head accept_node; 162 struct list_head node;
163 struct completion login_comp; 163 struct completion login_comp;
164 struct completion login_req_comp; 164 struct completion login_req_comp;
165 struct iser_tx_desc login_tx_desc; 165 struct iser_tx_desc login_tx_desc;
@@ -221,5 +221,6 @@ struct isert_np {
221 struct semaphore sem; 221 struct semaphore sem;
222 struct rdma_cm_id *cm_id; 222 struct rdma_cm_id *cm_id;
223 struct mutex mutex; 223 struct mutex mutex;
224 struct list_head accept_list; 224 struct list_head accepted;
225 struct list_head pending;
225}; 226};