Skip to content

Commit 63221ac

Browse files
rpearsonhpe-designjgunthorpe
authored andcommitted
RDMA/rxe: Fix ref error in rxe_av.c
The commit referenced below can take a reference to the AH which is never dropped. This only happens in the UD request path. This patch optionally passes that AH back to the caller so that it can hold the reference while the AV is being accessed and then drop it. Code to do this is added to rxe_req.c. The AV is also passed to rxe_prepare in rxe_net.c as an optimization. Fixes: e2fe06c ("RDMA/rxe: Lookup kernel AH from ah index in UD WQEs") Link: https://lore.kernel.org/r/20220304000808.225811-2-rpearsonhpe@gmail.com Signed-off-by: Bob Pearson <rpearsonhpe@gmail.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
1 parent 70f9252 commit 63221ac

5 files changed

Lines changed: 63 additions & 35 deletions

File tree

drivers/infiniband/sw/rxe/rxe_av.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,14 @@ void rxe_av_fill_ip_info(struct rxe_av *av, struct rdma_ah_attr *attr)
9999
av->network_type = type;
100100
}
101101

102-
struct rxe_av *rxe_get_av(struct rxe_pkt_info *pkt)
102+
struct rxe_av *rxe_get_av(struct rxe_pkt_info *pkt, struct rxe_ah **ahp)
103103
{
104104
struct rxe_ah *ah;
105105
u32 ah_num;
106106

107+
if (ahp)
108+
*ahp = NULL;
109+
107110
if (!pkt || !pkt->qp)
108111
return NULL;
109112

@@ -117,10 +120,22 @@ struct rxe_av *rxe_get_av(struct rxe_pkt_info *pkt)
117120
if (ah_num) {
118121
/* only new user provider or kernel client */
119122
ah = rxe_pool_get_index(&pkt->rxe->ah_pool, ah_num);
120-
if (!ah || ah->ah_num != ah_num || rxe_ah_pd(ah) != pkt->qp->pd) {
123+
if (!ah) {
121124
pr_warn("Unable to find AH matching ah_num\n");
122125
return NULL;
123126
}
127+
128+
if (rxe_ah_pd(ah) != pkt->qp->pd) {
129+
pr_warn("PDs don't match for AH and QP\n");
130+
rxe_drop_ref(ah);
131+
return NULL;
132+
}
133+
134+
if (ahp)
135+
*ahp = ah;
136+
else
137+
rxe_drop_ref(ah);
138+
124139
return &ah->av;
125140
}
126141

drivers/infiniband/sw/rxe/rxe_loc.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ void rxe_av_to_attr(struct rxe_av *av, struct rdma_ah_attr *attr);
1919

2020
void rxe_av_fill_ip_info(struct rxe_av *av, struct rdma_ah_attr *attr);
2121

22-
struct rxe_av *rxe_get_av(struct rxe_pkt_info *pkt);
22+
struct rxe_av *rxe_get_av(struct rxe_pkt_info *pkt, struct rxe_ah **ahp);
2323

2424
/* rxe_cq.c */
2525
int rxe_cq_chk_attr(struct rxe_dev *rxe, struct rxe_cq *cq,
@@ -94,7 +94,8 @@ void rxe_mw_cleanup(struct rxe_pool_elem *arg);
9494
/* rxe_net.c */
9595
struct sk_buff *rxe_init_packet(struct rxe_dev *rxe, struct rxe_av *av,
9696
int paylen, struct rxe_pkt_info *pkt);
97-
int rxe_prepare(struct rxe_pkt_info *pkt, struct sk_buff *skb);
97+
int rxe_prepare(struct rxe_av *av, struct rxe_pkt_info *pkt,
98+
struct sk_buff *skb);
9899
int rxe_xmit_packet(struct rxe_qp *qp, struct rxe_pkt_info *pkt,
99100
struct sk_buff *skb);
100101
const char *rxe_parent_name(struct rxe_dev *rxe, unsigned int port_num);

drivers/infiniband/sw/rxe/rxe_net.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -271,13 +271,13 @@ static void prepare_ipv6_hdr(struct dst_entry *dst, struct sk_buff *skb,
271271
ip6h->payload_len = htons(skb->len - sizeof(*ip6h));
272272
}
273273

274-
static int prepare4(struct rxe_pkt_info *pkt, struct sk_buff *skb)
274+
static int prepare4(struct rxe_av *av, struct rxe_pkt_info *pkt,
275+
struct sk_buff *skb)
275276
{
276277
struct rxe_qp *qp = pkt->qp;
277278
struct dst_entry *dst;
278279
bool xnet = false;
279280
__be16 df = htons(IP_DF);
280-
struct rxe_av *av = rxe_get_av(pkt);
281281
struct in_addr *saddr = &av->sgid_addr._sockaddr_in.sin_addr;
282282
struct in_addr *daddr = &av->dgid_addr._sockaddr_in.sin_addr;
283283

@@ -297,11 +297,11 @@ static int prepare4(struct rxe_pkt_info *pkt, struct sk_buff *skb)
297297
return 0;
298298
}
299299

300-
static int prepare6(struct rxe_pkt_info *pkt, struct sk_buff *skb)
300+
static int prepare6(struct rxe_av *av, struct rxe_pkt_info *pkt,
301+
struct sk_buff *skb)
301302
{
302303
struct rxe_qp *qp = pkt->qp;
303304
struct dst_entry *dst;
304-
struct rxe_av *av = rxe_get_av(pkt);
305305
struct in6_addr *saddr = &av->sgid_addr._sockaddr_in6.sin6_addr;
306306
struct in6_addr *daddr = &av->dgid_addr._sockaddr_in6.sin6_addr;
307307

@@ -322,16 +322,17 @@ static int prepare6(struct rxe_pkt_info *pkt, struct sk_buff *skb)
322322
return 0;
323323
}
324324

325-
int rxe_prepare(struct rxe_pkt_info *pkt, struct sk_buff *skb)
325+
int rxe_prepare(struct rxe_av *av, struct rxe_pkt_info *pkt,
326+
struct sk_buff *skb)
326327
{
327328
int err = 0;
328329

329330
if (skb->protocol == htons(ETH_P_IP))
330-
err = prepare4(pkt, skb);
331+
err = prepare4(av, pkt, skb);
331332
else if (skb->protocol == htons(ETH_P_IPV6))
332-
err = prepare6(pkt, skb);
333+
err = prepare6(av, pkt, skb);
333334

334-
if (ether_addr_equal(skb->dev->dev_addr, rxe_get_av(pkt)->dmac))
335+
if (ether_addr_equal(skb->dev->dev_addr, av->dmac))
335336
pkt->mask |= RXE_LOOPBACK_MASK;
336337

337338
return err;

drivers/infiniband/sw/rxe/rxe_req.c

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -358,14 +358,14 @@ static inline int get_mtu(struct rxe_qp *qp)
358358
}
359359

360360
static struct sk_buff *init_req_packet(struct rxe_qp *qp,
361+
struct rxe_av *av,
361362
struct rxe_send_wqe *wqe,
362363
int opcode, u32 payload,
363364
struct rxe_pkt_info *pkt)
364365
{
365366
struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
366367
struct sk_buff *skb;
367368
struct rxe_send_wr *ibwr = &wqe->wr;
368-
struct rxe_av *av;
369369
int pad = (-payload) & 0x3;
370370
int paylen;
371371
int solicited;
@@ -374,21 +374,9 @@ static struct sk_buff *init_req_packet(struct rxe_qp *qp,
374374

375375
/* length from start of bth to end of icrc */
376376
paylen = rxe_opcode[opcode].length + payload + pad + RXE_ICRC_SIZE;
377-
378-
/* pkt->hdr, port_num and mask are initialized in ifc layer */
379-
pkt->rxe = rxe;
380-
pkt->opcode = opcode;
381-
pkt->qp = qp;
382-
pkt->psn = qp->req.psn;
383-
pkt->mask = rxe_opcode[opcode].mask;
384-
pkt->paylen = paylen;
385-
pkt->wqe = wqe;
377+
pkt->paylen = paylen;
386378

387379
/* init skb */
388-
av = rxe_get_av(pkt);
389-
if (!av)
390-
return NULL;
391-
392380
skb = rxe_init_packet(rxe, av, paylen, pkt);
393381
if (unlikely(!skb))
394382
return NULL;
@@ -447,13 +435,13 @@ static struct sk_buff *init_req_packet(struct rxe_qp *qp,
447435
return skb;
448436
}
449437

450-
static int finish_packet(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
451-
struct rxe_pkt_info *pkt, struct sk_buff *skb,
452-
u32 paylen)
438+
static int finish_packet(struct rxe_qp *qp, struct rxe_av *av,
439+
struct rxe_send_wqe *wqe, struct rxe_pkt_info *pkt,
440+
struct sk_buff *skb, u32 paylen)
453441
{
454442
int err;
455443

456-
err = rxe_prepare(pkt, skb);
444+
err = rxe_prepare(av, pkt, skb);
457445
if (err)
458446
return err;
459447

@@ -608,6 +596,7 @@ static int rxe_do_local_ops(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
608596
int rxe_requester(void *arg)
609597
{
610598
struct rxe_qp *qp = (struct rxe_qp *)arg;
599+
struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
611600
struct rxe_pkt_info pkt;
612601
struct sk_buff *skb;
613602
struct rxe_send_wqe *wqe;
@@ -619,6 +608,8 @@ int rxe_requester(void *arg)
619608
struct rxe_send_wqe rollback_wqe;
620609
u32 rollback_psn;
621610
struct rxe_queue *q = qp->sq.queue;
611+
struct rxe_ah *ah;
612+
struct rxe_av *av;
622613

623614
rxe_add_ref(qp);
624615

@@ -705,24 +696,41 @@ int rxe_requester(void *arg)
705696
payload = mtu;
706697
}
707698

708-
skb = init_req_packet(qp, wqe, opcode, payload, &pkt);
699+
pkt.rxe = rxe;
700+
pkt.opcode = opcode;
701+
pkt.qp = qp;
702+
pkt.psn = qp->req.psn;
703+
pkt.mask = rxe_opcode[opcode].mask;
704+
pkt.wqe = wqe;
705+
706+
av = rxe_get_av(&pkt, &ah);
707+
if (unlikely(!av)) {
708+
pr_err("qp#%d Failed no address vector\n", qp_num(qp));
709+
wqe->status = IB_WC_LOC_QP_OP_ERR;
710+
goto err_drop_ah;
711+
}
712+
713+
skb = init_req_packet(qp, av, wqe, opcode, payload, &pkt);
709714
if (unlikely(!skb)) {
710715
pr_err("qp#%d Failed allocating skb\n", qp_num(qp));
711716
wqe->status = IB_WC_LOC_QP_OP_ERR;
712-
goto err;
717+
goto err_drop_ah;
713718
}
714719

715-
ret = finish_packet(qp, wqe, &pkt, skb, payload);
720+
ret = finish_packet(qp, av, wqe, &pkt, skb, payload);
716721
if (unlikely(ret)) {
717722
pr_debug("qp#%d Error during finish packet\n", qp_num(qp));
718723
if (ret == -EFAULT)
719724
wqe->status = IB_WC_LOC_PROT_ERR;
720725
else
721726
wqe->status = IB_WC_LOC_QP_OP_ERR;
722727
kfree_skb(skb);
723-
goto err;
728+
goto err_drop_ah;
724729
}
725730

731+
if (ah)
732+
rxe_drop_ref(ah);
733+
726734
/*
727735
* To prevent a race on wqe access between requester and completer,
728736
* wqe members state and psn need to be set before calling
@@ -751,6 +759,9 @@ int rxe_requester(void *arg)
751759

752760
goto next_wqe;
753761

762+
err_drop_ah:
763+
if (ah)
764+
rxe_drop_ref(ah);
754765
err:
755766
wqe->state = wqe_state_error;
756767
__rxe_do_task(&qp->comp.task);

drivers/infiniband/sw/rxe/rxe_resp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ static struct sk_buff *prepare_ack_packet(struct rxe_qp *qp,
633633
if (ack->mask & RXE_ATMACK_MASK)
634634
atmack_set_orig(ack, qp->resp.atomic_orig);
635635

636-
err = rxe_prepare(ack, skb);
636+
err = rxe_prepare(&qp->pri_av, ack, skb);
637637
if (err) {
638638
kfree_skb(skb);
639639
return NULL;

0 commit comments

Comments
 (0)