Skip to content

Commit 874d8df

Browse files
Steve WiseRoland Dreier
authored andcommitted
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>
1 parent 04b5d02 commit 874d8df

File tree

2 files changed

+17
-12
lines changed

2 files changed

+17
-12
lines changed

drivers/infiniband/hw/cxgb3/iwch_cm.c

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -282,18 +282,22 @@ static void *alloc_ep(int size, gfp_t gfp)
282282

283283
void __free_ep(struct kref *kref)
284284
{
285-
struct iwch_ep_common *epc;
286-
epc = container_of(kref, struct iwch_ep_common, kref);
287-
PDBG("%s ep %p state %s\n", __func__, epc, states[state_read(epc)]);
288-
kfree(epc);
285+
struct iwch_ep *ep;
286+
ep = container_of(container_of(kref, struct iwch_ep_common, kref),
287+
struct iwch_ep, com);
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);
289295
}
290296

291297
static void release_ep_resources(struct iwch_ep *ep)
292298
{
293299
PDBG("%s ep %p tid %d\n", __func__, ep, ep->hwtid);
294-
cxgb3_remove_tid(ep->com.tdev, (void *)ep, ep->hwtid);
295-
dst_release(ep->dst);
296-
l2t_release(L2DATA(ep->com.tdev), ep->l2t);
300+
ep->com.flags |= RELEASE_RESOURCES;
297301
put_ep(&ep->com);
298302
}
299303

@@ -1152,8 +1156,8 @@ static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
11521156
* We get 2 abort replies from the HW. The first one must
11531157
* be ignored except for scribbling that we need one more.
11541158
*/
1155-
if (!(ep->flags & ABORT_REQ_IN_PROGRESS)) {
1156-
ep->flags |= ABORT_REQ_IN_PROGRESS;
1159+
if (!(ep->com.flags & ABORT_REQ_IN_PROGRESS)) {
1160+
ep->com.flags |= ABORT_REQ_IN_PROGRESS;
11571161
return CPL_RET_BUF_DONE;
11581162
}
11591163

@@ -1557,8 +1561,8 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
15571561
* We get 2 peer aborts from the HW. The first one must
15581562
* be ignored except for scribbling that we need one more.
15591563
*/
1560-
if (!(ep->flags & PEER_ABORT_IN_PROGRESS)) {
1561-
ep->flags |= PEER_ABORT_IN_PROGRESS;
1564+
if (!(ep->com.flags & PEER_ABORT_IN_PROGRESS)) {
1565+
ep->com.flags |= PEER_ABORT_IN_PROGRESS;
15621566
return CPL_RET_BUF_DONE;
15631567
}
15641568

drivers/infiniband/hw/cxgb3/iwch_cm.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ enum iwch_ep_state {
147147
enum iwch_ep_flags {
148148
PEER_ABORT_IN_PROGRESS = (1 << 0),
149149
ABORT_REQ_IN_PROGRESS = (1 << 1),
150+
RELEASE_RESOURCES = (1 << 2),
150151
};
151152

152153
struct iwch_ep_common {
@@ -161,6 +162,7 @@ struct iwch_ep_common {
161162
wait_queue_head_t waitq;
162163
int rpl_done;
163164
int rpl_err;
165+
u32 flags;
164166
};
165167

166168
struct iwch_listen_ep {
@@ -188,7 +190,6 @@ struct iwch_ep {
188190
u16 plen;
189191
u32 ird;
190192
u32 ord;
191-
u32 flags;
192193
};
193194

194195
static inline struct iwch_ep *to_ep(struct iw_cm_id *cm_id)

0 commit comments

Comments
 (0)