From: Vipul Pandya Date: Tue, 20 Nov 2012 15:22:40 +0000 (-0800) Subject: RDMA/cxgb4: fix mpa version mismatch X-Git-Tag: vofed-3.5-x~14 X-Git-Url: https://openfabrics.org/gitweb/?a=commitdiff_plain;h=1039a5e6a7c6f808a0ba83dccd936ad351bc16c9;p=~emulex%2Ffor-vlad%2Fcompat-rdma.git RDMA/cxgb4: fix mpa version mismatch This patch fixes bug 2404 in OFED bugzilla Signed-off-by: Vipul Pandya --- diff --git a/linux-next-pending/0027-RDMA-cxgb4-endpoint-timeout-race-condition.patch b/linux-next-pending/0027-RDMA-cxgb4-endpoint-timeout-race-condition.patch new file mode 100644 index 0000000..e484915 --- /dev/null +++ b/linux-next-pending/0027-RDMA-cxgb4-endpoint-timeout-race-condition.patch @@ -0,0 +1,76 @@ +RDMA/cxgb4: endpoint timeout race condition + +The endpoint timeout logic had a race that could cause an endpoint +object to be freed while it was still on the timedout list. This +can happen if the timer is stopped after it had fired, but before +the timedout thread processed the endpoint timeout. + +diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c +--- a/drivers/infiniband/hw/cxgb4/cm.c 2012-11-19 15:09:38.780091885 +0530 ++++ b/drivers/infiniband/hw/cxgb4/cm.c 2012-11-20 17:50:36.002975441 +0530 +@@ -159,10 +159,12 @@ static void start_ep_timer(struct c4iw_e + { + PDBG("%s ep %p\n", __func__, ep); + if (timer_pending(&ep->timer)) { +- PDBG("%s stopped / restarted timer ep %p\n", __func__, ep); +- del_timer_sync(&ep->timer); +- } else +- c4iw_get_ep(&ep->com); ++ pr_err("%s timer already started! " "ep %p \n", ++ __func__, ep); ++ return; ++ } ++ clear_bit(TIMEOUT, &ep->com.flags); ++ c4iw_get_ep(&ep->com); + ep->timer.expires = jiffies + ep_timeout_secs * HZ; + ep->timer.data = (unsigned long)ep; + ep->timer.function = ep_timeout; +@@ -171,15 +173,10 @@ static void start_ep_timer(struct c4iw_e + + static void stop_ep_timer(struct c4iw_ep *ep) + { +- PDBG("%s ep %p\n", __func__, ep); +- if (!timer_pending(&ep->timer)) { +- printk(KERN_ERR "%s timer stopped when its not running! " +- "ep %p state %u\n", __func__, ep, ep->com.state); +- WARN_ON(1); +- return; +- } ++ PDBG("%s ep %p stopping\n", __func__, ep); + del_timer_sync(&ep->timer); +- c4iw_put_ep(&ep->com); ++ if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) ++ c4iw_put_ep(&ep->com); + } + + static int c4iw_l2t_send(struct c4iw_rdev *rdev, struct sk_buff *skb, +@@ -3259,11 +3256,16 @@ static DECLARE_WORK(skb_work, process_wo + static void ep_timeout(unsigned long arg) + { + struct c4iw_ep *ep = (struct c4iw_ep *)arg; ++ int kickit = 0; + + spin_lock(&timeout_lock); +- list_add_tail(&ep->entry, &timeout_list); ++ if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) { ++ list_add_tail(&ep->entry, &timeout_list); ++ kickit = 1; ++ } + spin_unlock(&timeout_lock); +- queue_work(workq, &skb_work); ++ if (kickit) ++ queue_work(workq, &skb_work); + } + + /* +diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h 2012-11-19 15:09:38.779091885 +0530 ++++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h 2012-11-20 17:56:52.231994435 +0530 +@@ -720,6 +720,7 @@ enum c4iw_ep_flags { + ABORT_REQ_IN_PROGRESS = 1, + RELEASE_RESOURCES = 2, + CLOSE_SENT = 3, ++ TIMEOUT = 4, + QP_REFERENCED = 5, + }; + diff --git a/linux-next-pending/0028-RDMA-cxgb4-dont-reconnect-on-abort.patch b/linux-next-pending/0028-RDMA-cxgb4-dont-reconnect-on-abort.patch new file mode 100644 index 0000000..fd51139 --- /dev/null +++ b/linux-next-pending/0028-RDMA-cxgb4-dont-reconnect-on-abort.patch @@ -0,0 +1,56 @@ +RDMA/cxgb4: don't reconnect on abort for mpa_rev 1 + +only reconnect if the endpoint wasn't freed. + +peer_abort() should only attempt to reconnect if the endpoint wasn't freed. +Also remove hwtid from the debugfs idr. + +Add missing check for peer2peer in MPAv2 code + +use correct mpa version on reject. + +diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c +--- a/drivers/infiniband/hw/cxgb4/cm.c 2012-11-19 15:09:38.780091885 +0530 ++++ b/drivers/infiniband/hw/cxgb4/cm.c 2012-11-19 19:04:44.528809027 +0530 +@@ -287,10 +287,10 @@ void _c4iw_free_ep(struct kref *kref) + if (test_bit(QP_REFERENCED, &ep->com.flags)) + deref_qp(ep); + if (test_bit(RELEASE_RESOURCES, &ep->com.flags)) { ++ remove_handle(ep->com.dev, &ep->com.dev->hwtid_idr, ep->hwtid); + cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, ep->hwtid); + dst_release(ep->dst); + cxgb4_l2t_release(ep->l2t); +- remove_handle(ep->com.dev, &ep->com.dev->hwtid_idr, ep->hwtid); + } + kfree(ep); + } +@@ -723,7 +723,7 @@ static int send_mpa_reject(struct c4iw_e + memset(mpa, 0, sizeof(*mpa)); + memcpy(mpa->key, MPA_KEY_REP, sizeof(mpa->key)); + mpa->flags = MPA_REJECT; +- mpa->revision = mpa_rev; ++ mpa->revision = ep->mpa_attr.version; + mpa->private_data_size = htons(plen); + + if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn) { +@@ -2226,7 +2226,7 @@ static int peer_abort(struct c4iw_dev *d + break; + case MPA_REQ_SENT: + stop_ep_timer(ep); +- if (mpa_rev == 2 && ep->tried_with_mpa_v1) ++ if (mpa_rev == 1 || (mpa_rev == 2 && ep->tried_with_mpa_v1)) + connect_reply_upcall(ep, -ECONNRESET); + else { + /* +@@ -2298,9 +2298,8 @@ static int peer_abort(struct c4iw_dev *d + out: + if (release) + release_ep_resources(ep); +- +- /* retry with mpa-v1 */ +- if (ep && ep->retry_with_mpa_v1) { ++ else if (ep->retry_with_mpa_v1) { ++ remove_handle(ep->com.dev, &ep->com.dev->hwtid_idr, ep->hwtid); + cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, ep->hwtid); + dst_release(ep->dst); + cxgb4_l2t_release(ep->l2t); diff --git a/linux-next-pending/0029-RDMA-cxgb4-fix-mpa-version-mismatch.patch b/linux-next-pending/0029-RDMA-cxgb4-fix-mpa-version-mismatch.patch new file mode 100644 index 0000000..b3963d6 --- /dev/null +++ b/linux-next-pending/0029-RDMA-cxgb4-fix-mpa-version-mismatch.patch @@ -0,0 +1,59 @@ +RDMA/cxgb4: Don't wakeup threads for MPAv2 + +Don't wakeup threads blocked in rdma_init/rdma_fini if we are on +MPAv2, and want to retry connection with MPAv1. + +Stop ep-timer on getting MPA version mismatch, before doing the +abort_connection - in process_mpa_request. + +Take care to stop ep-timer in error paths for process_mpa_request. + +diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c +--- a/drivers/infiniband/hw/cxgb4/cm.c 2012-11-19 15:09:38.780091885 +0530 ++++ b/drivers/infiniband/hw/cxgb4/cm.c 2012-11-19 17:24:22.842503571 +0530 +@@ -1324,11 +1324,13 @@ static void process_mpa_request(struct c + if (mpa->revision > mpa_rev) { + printk(KERN_ERR MOD "%s MPA version mismatch. Local = %d," + " Received = %d\n", __func__, mpa_rev, mpa->revision); ++ stop_ep_timer(ep); + abort_connection(ep, skb, GFP_KERNEL); + return; + } + + if (memcmp(mpa->key, MPA_KEY_REQ, sizeof(mpa->key))) { ++ stop_ep_timer(ep); + abort_connection(ep, skb, GFP_KERNEL); + return; + } +@@ -1339,6 +1341,7 @@ static void process_mpa_request(struct c + * Fail if there's too much private data. + */ + if (plen > MPA_MAX_PRIVATE_DATA) { ++ stop_ep_timer(ep); + abort_connection(ep, skb, GFP_KERNEL); + return; + } +@@ -1347,6 +1350,7 @@ static void process_mpa_request(struct c + * If plen does not account for pkt size + */ + if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) { ++ stop_ep_timer(ep); + abort_connection(ep, skb, GFP_KERNEL); + return; + } +@@ -3352,8 +3356,14 @@ static int peer_abort_intr(struct c4iw_d + + /* + * Wake up any threads in rdma_init() or rdma_fini(). ++ * However, if we are on MPAv2 and want to retry with MPAv1 ++ * then, don't wake up yet. + */ +- c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET); ++ if (mpa_rev == 2 && !ep->tried_with_mpa_v1) { ++ if (ep->com.state != MPA_REQ_SENT) ++ c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET); ++ } else ++ c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET); + sched(dev, skb); + return 0; + }