diff options
author | Steve Wise <swise@opengridcomputing.com> | 2009-09-05 23:22:38 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2009-09-05 23:22:38 -0400 |
commit | 6e47fe43502ba6dfe86d556661795d9bb0361309 (patch) | |
tree | bc29f159253320abf8d55ceac0b06dda3ddd3b7d /drivers/infiniband/hw | |
parent | fa0d4c11c4b6eb49708b82b638ceb0761152f46a (diff) |
RDMA/cxgb3: Don't free endpoints early
- Keep ref on connection request endpoints until either accepted or
rejected so it doesn't get freed early.
- Endpoint flags now need to be set via atomic bitops because they can
be set on both the iw_cxgb3 workqueue thread and user disconnect
threads.
- Don't move out of CLOSING too early due to multiple calls to
iwch_ep_disconnect.
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw')
-rw-r--r-- | drivers/infiniband/hw/cxgb3/iwch_cm.c | 52 | ||||
-rw-r--r-- | drivers/infiniband/hw/cxgb3/iwch_cm.h | 9 |
2 files changed, 33 insertions, 28 deletions
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 52d7bb0c2a12..7f22f1797718 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c | |||
@@ -286,7 +286,7 @@ void __free_ep(struct kref *kref) | |||
286 | ep = container_of(container_of(kref, struct iwch_ep_common, kref), | 286 | ep = container_of(container_of(kref, struct iwch_ep_common, kref), |
287 | struct iwch_ep, com); | 287 | struct iwch_ep, com); |
288 | PDBG("%s ep %p state %s\n", __func__, ep, states[state_read(&ep->com)]); | 288 | PDBG("%s ep %p state %s\n", __func__, ep, states[state_read(&ep->com)]); |
289 | if (ep->com.flags & RELEASE_RESOURCES) { | 289 | if (test_bit(RELEASE_RESOURCES, &ep->com.flags)) { |
290 | cxgb3_remove_tid(ep->com.tdev, (void *)ep, ep->hwtid); | 290 | cxgb3_remove_tid(ep->com.tdev, (void *)ep, ep->hwtid); |
291 | dst_release(ep->dst); | 291 | dst_release(ep->dst); |
292 | l2t_release(L2DATA(ep->com.tdev), ep->l2t); | 292 | l2t_release(L2DATA(ep->com.tdev), ep->l2t); |
@@ -297,7 +297,7 @@ void __free_ep(struct kref *kref) | |||
297 | static void release_ep_resources(struct iwch_ep *ep) | 297 | static void release_ep_resources(struct iwch_ep *ep) |
298 | { | 298 | { |
299 | PDBG("%s ep %p tid %d\n", __func__, ep, ep->hwtid); | 299 | PDBG("%s ep %p tid %d\n", __func__, ep, ep->hwtid); |
300 | ep->com.flags |= RELEASE_RESOURCES; | 300 | set_bit(RELEASE_RESOURCES, &ep->com.flags); |
301 | put_ep(&ep->com); | 301 | put_ep(&ep->com); |
302 | } | 302 | } |
303 | 303 | ||
@@ -786,10 +786,12 @@ static void connect_request_upcall(struct iwch_ep *ep) | |||
786 | event.private_data_len = ep->plen; | 786 | event.private_data_len = ep->plen; |
787 | event.private_data = ep->mpa_pkt + sizeof(struct mpa_message); | 787 | event.private_data = ep->mpa_pkt + sizeof(struct mpa_message); |
788 | event.provider_data = ep; | 788 | event.provider_data = ep; |
789 | if (state_read(&ep->parent_ep->com) != DEAD) | 789 | if (state_read(&ep->parent_ep->com) != DEAD) { |
790 | get_ep(&ep->com); | ||
790 | ep->parent_ep->com.cm_id->event_handler( | 791 | ep->parent_ep->com.cm_id->event_handler( |
791 | ep->parent_ep->com.cm_id, | 792 | ep->parent_ep->com.cm_id, |
792 | &event); | 793 | &event); |
794 | } | ||
793 | put_ep(&ep->parent_ep->com); | 795 | put_ep(&ep->parent_ep->com); |
794 | ep->parent_ep = NULL; | 796 | ep->parent_ep = NULL; |
795 | } | 797 | } |
@@ -1156,8 +1158,7 @@ static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) | |||
1156 | * We get 2 abort replies from the HW. The first one must | 1158 | * We get 2 abort replies from the HW. The first one must |
1157 | * be ignored except for scribbling that we need one more. | 1159 | * be ignored except for scribbling that we need one more. |
1158 | */ | 1160 | */ |
1159 | if (!(ep->com.flags & ABORT_REQ_IN_PROGRESS)) { | 1161 | if (!test_and_set_bit(ABORT_REQ_IN_PROGRESS, &ep->com.flags)) { |
1160 | ep->com.flags |= ABORT_REQ_IN_PROGRESS; | ||
1161 | return CPL_RET_BUF_DONE; | 1162 | return CPL_RET_BUF_DONE; |
1162 | } | 1163 | } |
1163 | 1164 | ||
@@ -1480,7 +1481,6 @@ static int peer_close(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) | |||
1480 | * rejects the CR. | 1481 | * rejects the CR. |
1481 | */ | 1482 | */ |
1482 | __state_set(&ep->com, CLOSING); | 1483 | __state_set(&ep->com, CLOSING); |
1483 | get_ep(&ep->com); | ||
1484 | break; | 1484 | break; |
1485 | case MPA_REP_SENT: | 1485 | case MPA_REP_SENT: |
1486 | __state_set(&ep->com, CLOSING); | 1486 | __state_set(&ep->com, CLOSING); |
@@ -1561,8 +1561,7 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) | |||
1561 | * We get 2 peer aborts from the HW. The first one must | 1561 | * We get 2 peer aborts from the HW. The first one must |
1562 | * be ignored except for scribbling that we need one more. | 1562 | * be ignored except for scribbling that we need one more. |
1563 | */ | 1563 | */ |
1564 | if (!(ep->com.flags & PEER_ABORT_IN_PROGRESS)) { | 1564 | if (!test_and_set_bit(PEER_ABORT_IN_PROGRESS, &ep->com.flags)) { |
1565 | ep->com.flags |= PEER_ABORT_IN_PROGRESS; | ||
1566 | return CPL_RET_BUF_DONE; | 1565 | return CPL_RET_BUF_DONE; |
1567 | } | 1566 | } |
1568 | 1567 | ||
@@ -1591,7 +1590,6 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) | |||
1591 | * the reference on it until the ULP accepts or | 1590 | * the reference on it until the ULP accepts or |
1592 | * rejects the CR. | 1591 | * rejects the CR. |
1593 | */ | 1592 | */ |
1594 | get_ep(&ep->com); | ||
1595 | break; | 1593 | break; |
1596 | case MORIBUND: | 1594 | case MORIBUND: |
1597 | case CLOSING: | 1595 | case CLOSING: |
@@ -1797,6 +1795,7 @@ int iwch_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len) | |||
1797 | err = send_mpa_reject(ep, pdata, pdata_len); | 1795 | err = send_mpa_reject(ep, pdata, pdata_len); |
1798 | err = iwch_ep_disconnect(ep, 0, GFP_KERNEL); | 1796 | err = iwch_ep_disconnect(ep, 0, GFP_KERNEL); |
1799 | } | 1797 | } |
1798 | put_ep(&ep->com); | ||
1800 | return 0; | 1799 | return 0; |
1801 | } | 1800 | } |
1802 | 1801 | ||
@@ -1810,8 +1809,10 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) | |||
1810 | struct iwch_qp *qp = get_qhp(h, conn_param->qpn); | 1809 | struct iwch_qp *qp = get_qhp(h, conn_param->qpn); |
1811 | 1810 | ||
1812 | PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid); | 1811 | PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid); |
1813 | if (state_read(&ep->com) == DEAD) | 1812 | if (state_read(&ep->com) == DEAD) { |
1814 | return -ECONNRESET; | 1813 | err = -ECONNRESET; |
1814 | goto err; | ||
1815 | } | ||
1815 | 1816 | ||
1816 | BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD); | 1817 | BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD); |
1817 | BUG_ON(!qp); | 1818 | BUG_ON(!qp); |
@@ -1819,7 +1820,8 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) | |||
1819 | if ((conn_param->ord > qp->rhp->attr.max_rdma_read_qp_depth) || | 1820 | if ((conn_param->ord > qp->rhp->attr.max_rdma_read_qp_depth) || |
1820 | (conn_param->ird > qp->rhp->attr.max_rdma_reads_per_qp)) { | 1821 | (conn_param->ird > qp->rhp->attr.max_rdma_reads_per_qp)) { |
1821 | abort_connection(ep, NULL, GFP_KERNEL); | 1822 | abort_connection(ep, NULL, GFP_KERNEL); |
1822 | return -EINVAL; | 1823 | err = -EINVAL; |
1824 | goto err; | ||
1823 | } | 1825 | } |
1824 | 1826 | ||
1825 | cm_id->add_ref(cm_id); | 1827 | cm_id->add_ref(cm_id); |
@@ -1836,8 +1838,6 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) | |||
1836 | 1838 | ||
1837 | PDBG("%s %d ird %d ord %d\n", __func__, __LINE__, ep->ird, ep->ord); | 1839 | PDBG("%s %d ird %d ord %d\n", __func__, __LINE__, ep->ird, ep->ord); |
1838 | 1840 | ||
1839 | get_ep(&ep->com); | ||
1840 | |||
1841 | /* bind QP to EP and move to RTS */ | 1841 | /* bind QP to EP and move to RTS */ |
1842 | attrs.mpa_attr = ep->mpa_attr; | 1842 | attrs.mpa_attr = ep->mpa_attr; |
1843 | attrs.max_ird = ep->ird; | 1843 | attrs.max_ird = ep->ird; |
@@ -1855,30 +1855,31 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) | |||
1855 | err = iwch_modify_qp(ep->com.qp->rhp, | 1855 | err = iwch_modify_qp(ep->com.qp->rhp, |
1856 | ep->com.qp, mask, &attrs, 1); | 1856 | ep->com.qp, mask, &attrs, 1); |
1857 | if (err) | 1857 | if (err) |
1858 | goto err; | 1858 | goto err1; |
1859 | 1859 | ||
1860 | /* if needed, wait for wr_ack */ | 1860 | /* if needed, wait for wr_ack */ |
1861 | if (iwch_rqes_posted(qp)) { | 1861 | if (iwch_rqes_posted(qp)) { |
1862 | wait_event(ep->com.waitq, ep->com.rpl_done); | 1862 | wait_event(ep->com.waitq, ep->com.rpl_done); |
1863 | err = ep->com.rpl_err; | 1863 | err = ep->com.rpl_err; |
1864 | if (err) | 1864 | if (err) |
1865 | goto err; | 1865 | goto err1; |
1866 | } | 1866 | } |
1867 | 1867 | ||
1868 | err = send_mpa_reply(ep, conn_param->private_data, | 1868 | err = send_mpa_reply(ep, conn_param->private_data, |
1869 | conn_param->private_data_len); | 1869 | conn_param->private_data_len); |
1870 | if (err) | 1870 | if (err) |
1871 | goto err; | 1871 | goto err1; |
1872 | 1872 | ||
1873 | 1873 | ||
1874 | state_set(&ep->com, FPDU_MODE); | 1874 | state_set(&ep->com, FPDU_MODE); |
1875 | established_upcall(ep); | 1875 | established_upcall(ep); |
1876 | put_ep(&ep->com); | 1876 | put_ep(&ep->com); |
1877 | return 0; | 1877 | return 0; |
1878 | err: | 1878 | err1: |
1879 | ep->com.cm_id = NULL; | 1879 | ep->com.cm_id = NULL; |
1880 | ep->com.qp = NULL; | 1880 | ep->com.qp = NULL; |
1881 | cm_id->rem_ref(cm_id); | 1881 | cm_id->rem_ref(cm_id); |
1882 | err: | ||
1882 | put_ep(&ep->com); | 1883 | put_ep(&ep->com); |
1883 | return err; | 1884 | return err; |
1884 | } | 1885 | } |
@@ -2097,14 +2098,17 @@ int iwch_ep_disconnect(struct iwch_ep *ep, int abrupt, gfp_t gfp) | |||
2097 | ep->com.state = CLOSING; | 2098 | ep->com.state = CLOSING; |
2098 | start_ep_timer(ep); | 2099 | start_ep_timer(ep); |
2099 | } | 2100 | } |
2101 | set_bit(CLOSE_SENT, &ep->com.flags); | ||
2100 | break; | 2102 | break; |
2101 | case CLOSING: | 2103 | case CLOSING: |
2102 | close = 1; | 2104 | if (!test_and_set_bit(CLOSE_SENT, &ep->com.flags)) { |
2103 | if (abrupt) { | 2105 | close = 1; |
2104 | stop_ep_timer(ep); | 2106 | if (abrupt) { |
2105 | ep->com.state = ABORTING; | 2107 | stop_ep_timer(ep); |
2106 | } else | 2108 | ep->com.state = ABORTING; |
2107 | ep->com.state = MORIBUND; | 2109 | } else |
2110 | ep->com.state = MORIBUND; | ||
2111 | } | ||
2108 | break; | 2112 | break; |
2109 | case MORIBUND: | 2113 | case MORIBUND: |
2110 | case ABORTING: | 2114 | case ABORTING: |
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h index 43c0aea7eadc..b9efadfffb4f 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.h +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h | |||
@@ -145,9 +145,10 @@ enum iwch_ep_state { | |||
145 | }; | 145 | }; |
146 | 146 | ||
147 | enum iwch_ep_flags { | 147 | enum iwch_ep_flags { |
148 | PEER_ABORT_IN_PROGRESS = (1 << 0), | 148 | PEER_ABORT_IN_PROGRESS = 0, |
149 | ABORT_REQ_IN_PROGRESS = (1 << 1), | 149 | ABORT_REQ_IN_PROGRESS = 1, |
150 | RELEASE_RESOURCES = (1 << 2), | 150 | RELEASE_RESOURCES = 2, |
151 | CLOSE_SENT = 3, | ||
151 | }; | 152 | }; |
152 | 153 | ||
153 | struct iwch_ep_common { | 154 | struct iwch_ep_common { |
@@ -162,7 +163,7 @@ struct iwch_ep_common { | |||
162 | wait_queue_head_t waitq; | 163 | wait_queue_head_t waitq; |
163 | int rpl_done; | 164 | int rpl_done; |
164 | int rpl_err; | 165 | int rpl_err; |
165 | u32 flags; | 166 | unsigned long flags; |
166 | }; | 167 | }; |
167 | 168 | ||
168 | struct iwch_listen_ep { | 169 | struct iwch_listen_ep { |