diff options
author | Steve Wise <swise@opengridcomputing.com> | 2009-03-30 11:37:59 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2009-03-30 11:37:59 -0400 |
commit | 874d8df5ed6e36fed07b524c266f6a96dd6d10d9 (patch) | |
tree | 22fe735a0a00fda013e8514bdc00a5a31e612b77 /drivers/infiniband/hw/cxgb3 | |
parent | 04b5d028f50ff05a8f9ae049ee71f8fdfcf1f5de (diff) |
RDMA/cxgb3: Release dependent resources only when endpoint memory is freed.
The cxgb3 l2t entry, hwtid, and dst entry were being released before
all the iwch_ep references were released. This can cause a crash in
t3_l2t_send_slow() and other places where the l2t entry is used.
The fix is to defer releasing these resources until all endpoint
references are gone.
Details:
- move flags field to the iwch_ep_common struct.
- add a flag indicating resources are to be released.
- release resources at endpoint free time instead of close/abort time.
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw/cxgb3')
-rw-r--r-- | drivers/infiniband/hw/cxgb3/iwch_cm.c | 26 | ||||
-rw-r--r-- | drivers/infiniband/hw/cxgb3/iwch_cm.h | 3 |
2 files changed, 17 insertions, 12 deletions
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 59e1c5f00785..fef3f1ae7225 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c | |||
@@ -282,18 +282,22 @@ static void *alloc_ep(int size, gfp_t gfp) | |||
282 | 282 | ||
283 | void __free_ep(struct kref *kref) | 283 | void __free_ep(struct kref *kref) |
284 | { | 284 | { |
285 | struct iwch_ep_common *epc; | 285 | struct iwch_ep *ep; |
286 | epc = container_of(kref, struct iwch_ep_common, kref); | 286 | ep = container_of(container_of(kref, struct iwch_ep_common, kref), |
287 | PDBG("%s ep %p state %s\n", __func__, epc, states[state_read(epc)]); | 287 | struct iwch_ep, com); |
288 | kfree(epc); | 288 | PDBG("%s ep %p state %s\n", __func__, ep, states[state_read(&ep->com)]); |
289 | if (ep->com.flags & RELEASE_RESOURCES) { | ||
290 | cxgb3_remove_tid(ep->com.tdev, (void *)ep, ep->hwtid); | ||
291 | dst_release(ep->dst); | ||
292 | l2t_release(L2DATA(ep->com.tdev), ep->l2t); | ||
293 | } | ||
294 | kfree(ep); | ||
289 | } | 295 | } |
290 | 296 | ||
291 | static void release_ep_resources(struct iwch_ep *ep) | 297 | static void release_ep_resources(struct iwch_ep *ep) |
292 | { | 298 | { |
293 | PDBG("%s ep %p tid %d\n", __func__, ep, ep->hwtid); | 299 | PDBG("%s ep %p tid %d\n", __func__, ep, ep->hwtid); |
294 | cxgb3_remove_tid(ep->com.tdev, (void *)ep, ep->hwtid); | 300 | ep->com.flags |= RELEASE_RESOURCES; |
295 | dst_release(ep->dst); | ||
296 | l2t_release(L2DATA(ep->com.tdev), ep->l2t); | ||
297 | put_ep(&ep->com); | 301 | put_ep(&ep->com); |
298 | } | 302 | } |
299 | 303 | ||
@@ -1152,8 +1156,8 @@ static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) | |||
1152 | * We get 2 abort replies from the HW. The first one must | 1156 | * We get 2 abort replies from the HW. The first one must |
1153 | * be ignored except for scribbling that we need one more. | 1157 | * be ignored except for scribbling that we need one more. |
1154 | */ | 1158 | */ |
1155 | if (!(ep->flags & ABORT_REQ_IN_PROGRESS)) { | 1159 | if (!(ep->com.flags & ABORT_REQ_IN_PROGRESS)) { |
1156 | ep->flags |= ABORT_REQ_IN_PROGRESS; | 1160 | ep->com.flags |= ABORT_REQ_IN_PROGRESS; |
1157 | return CPL_RET_BUF_DONE; | 1161 | return CPL_RET_BUF_DONE; |
1158 | } | 1162 | } |
1159 | 1163 | ||
@@ -1557,8 +1561,8 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) | |||
1557 | * 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 |
1558 | * be ignored except for scribbling that we need one more. | 1562 | * be ignored except for scribbling that we need one more. |
1559 | */ | 1563 | */ |
1560 | if (!(ep->flags & PEER_ABORT_IN_PROGRESS)) { | 1564 | if (!(ep->com.flags & PEER_ABORT_IN_PROGRESS)) { |
1561 | ep->flags |= PEER_ABORT_IN_PROGRESS; | 1565 | ep->com.flags |= PEER_ABORT_IN_PROGRESS; |
1562 | return CPL_RET_BUF_DONE; | 1566 | return CPL_RET_BUF_DONE; |
1563 | } | 1567 | } |
1564 | 1568 | ||
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h index d7c7e09f0996..43c0aea7eadc 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.h +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h | |||
@@ -147,6 +147,7 @@ enum iwch_ep_state { | |||
147 | enum iwch_ep_flags { | 147 | enum iwch_ep_flags { |
148 | PEER_ABORT_IN_PROGRESS = (1 << 0), | 148 | PEER_ABORT_IN_PROGRESS = (1 << 0), |
149 | ABORT_REQ_IN_PROGRESS = (1 << 1), | 149 | ABORT_REQ_IN_PROGRESS = (1 << 1), |
150 | RELEASE_RESOURCES = (1 << 2), | ||
150 | }; | 151 | }; |
151 | 152 | ||
152 | struct iwch_ep_common { | 153 | struct iwch_ep_common { |
@@ -161,6 +162,7 @@ struct iwch_ep_common { | |||
161 | wait_queue_head_t waitq; | 162 | wait_queue_head_t waitq; |
162 | int rpl_done; | 163 | int rpl_done; |
163 | int rpl_err; | 164 | int rpl_err; |
165 | u32 flags; | ||
164 | }; | 166 | }; |
165 | 167 | ||
166 | struct iwch_listen_ep { | 168 | struct iwch_listen_ep { |
@@ -188,7 +190,6 @@ struct iwch_ep { | |||
188 | u16 plen; | 190 | u16 plen; |
189 | u32 ird; | 191 | u32 ird; |
190 | u32 ord; | 192 | u32 ord; |
191 | u32 flags; | ||
192 | }; | 193 | }; |
193 | 194 | ||
194 | static inline struct iwch_ep *to_ep(struct iw_cm_id *cm_id) | 195 | static inline struct iwch_ep *to_ep(struct iw_cm_id *cm_id) |