@@ -522,11 +522,8 @@ static void rxe_drain_resp_pkts(struct rxe_qp *qp, bool notify)
struct rxe_send_wqe *wqe;
struct rxe_queue *q = qp->sq.queue;
- while ((skb = skb_dequeue(&qp->resp_pkts))) {
- rxe_drop_ref(qp);
- kfree_skb(skb);
- ib_device_put(qp->ibqp.device);
- }
+ while ((skb = skb_dequeue(&qp->resp_pkts)))
+ rxe_free_pkt(SKB_TO_PKT(skb));
while ((wqe = queue_head(q, q->type))) {
if (notify) {
@@ -538,17 +535,6 @@ static void rxe_drain_resp_pkts(struct rxe_qp *qp, bool notify)
}
}
-static void free_pkt(struct rxe_pkt_info *pkt)
-{
- struct sk_buff *skb = PKT_TO_SKB(pkt);
- struct rxe_qp *qp = pkt->qp;
- struct ib_device *dev = qp->ibqp.device;
-
- kfree_skb(skb);
- rxe_drop_ref(qp);
- ib_device_put(dev);
-}
-
int rxe_completer(void *arg)
{
struct rxe_qp *qp = (struct rxe_qp *)arg;
@@ -757,7 +743,7 @@ int rxe_completer(void *arg)
done:
if (pkt)
- free_pkt(pkt);
+ rxe_free_pkt(pkt);
rxe_drop_ref(qp);
return ret;
@@ -12,6 +12,7 @@
* sk_buff for received packets.
*/
struct rxe_pkt_info {
+ struct sk_buff *skb; /* back pointer to skb */
struct rxe_dev *rxe; /* device that owns packet */
struct rxe_qp *qp; /* qp that owns packet */
struct rxe_send_wqe *wqe; /* send wqe */
@@ -24,16 +25,22 @@ struct rxe_pkt_info {
u8 opcode; /* bth opcode of packet */
};
+/* rxe info in skb->cb */
+struct rxe_cb {
+ struct rxe_pkt_info *pkt; /* pointer to pkt info */
+};
+
+#define RXE_CB(skb) ((struct rxe_cb *)skb->cb)
+
/* Macros should be used only for received skb */
static inline struct rxe_pkt_info *SKB_TO_PKT(struct sk_buff *skb)
{
- BUILD_BUG_ON(sizeof(struct rxe_pkt_info) > sizeof(skb->cb));
- return (void *)skb->cb;
+ return RXE_CB(skb)->pkt;
}
static inline struct sk_buff *PKT_TO_SKB(struct rxe_pkt_info *pkt)
{
- return container_of((void *)pkt, struct sk_buff, cb);
+ return pkt->skb;
}
/*
@@ -139,6 +139,9 @@ static inline int qp_mtu(struct rxe_qp *qp)
return IB_MTU_4096;
}
+/* rxe_recv.c */
+void rxe_free_pkt(struct rxe_pkt_info *pkt);
+
static inline int rcv_wqe_size(int max_sge)
{
return sizeof(struct rxe_recv_wqe) +
@@ -155,7 +155,7 @@ static int rxe_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
struct udphdr *udph;
struct rxe_dev *rxe;
struct net_device *ndev = skb->dev;
- struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
+ struct rxe_pkt_info *pkt;
/* takes a reference on rxe->ib_dev
* drop when skb is freed
@@ -172,6 +172,10 @@ static int rxe_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
goto drop;
}
+ pkt = kzalloc(sizeof(*pkt), GFP_ATOMIC);
+ RXE_CB(skb)->pkt = pkt;
+ pkt->skb = skb;
+
udph = udp_hdr(skb);
pkt->rxe = rxe;
pkt->port_num = 1;
@@ -407,15 +411,21 @@ static int rxe_send(struct sk_buff *skb, struct rxe_pkt_info *pkt)
*/
static int rxe_loopback(struct sk_buff *skb, struct rxe_pkt_info *pkt)
{
- memcpy(SKB_TO_PKT(skb), pkt, sizeof(*pkt));
+ struct rxe_pkt_info *new_pkt;
if (skb->protocol == htons(ETH_P_IP))
skb_pull(skb, sizeof(struct iphdr));
else
skb_pull(skb, sizeof(struct ipv6hdr));
+ new_pkt = kzalloc(sizeof(*new_pkt), GFP_ATOMIC);
+ memcpy(new_pkt, pkt, sizeof(*pkt));
+ RXE_CB(skb)->pkt = new_pkt;
+ new_pkt->skb = skb;
+
if (WARN_ON(!ib_device_try_get(&pkt->rxe->ib_dev))) {
kfree_skb(skb);
+ kfree(new_pkt);
return -EIO;
}
@@ -9,6 +9,20 @@
#include "rxe.h"
#include "rxe_loc.h"
+void rxe_free_pkt(struct rxe_pkt_info *pkt)
+{
+ struct sk_buff *skb = PKT_TO_SKB(pkt);
+ struct rxe_qp *qp = pkt->qp;
+
+ if (qp)
+ rxe_drop_ref(qp);
+
+ ib_device_put(&pkt->rxe->ib_dev);
+
+ kfree_skb(skb);
+ kfree(pkt);
+}
+
/* check that QP matches packet opcode type and is in a valid state */
static int check_type_state(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
struct rxe_qp *qp)
@@ -279,14 +293,22 @@ static void rxe_rcv_mcast_pkt(struct rxe_dev *rxe, struct sk_buff *skb)
cskb = skb_clone(skb, GFP_ATOMIC);
if (unlikely(!cskb))
- continue;
+ break;
+
+ cpkt = kzalloc(sizeof(*cpkt), GFP_ATOMIC);
+ if (unlikely(!cpkt)) {
+ kfree_skb(cskb);
+ break;
+ }
+ RXE_CB(cskb)->pkt = cpkt;
+ cpkt->skb = cskb;
if (WARN_ON(!ib_device_try_get(&rxe->ib_dev))) {
kfree_skb(cskb);
+ kfree(cpkt);
break;
}
- cpkt = SKB_TO_PKT(cskb);
cpkt->qp = qp;
rxe_add_ref(qp);
rxe_rcv_pkt(cpkt, cskb);
@@ -310,8 +332,7 @@ static void rxe_rcv_mcast_pkt(struct rxe_dev *rxe, struct sk_buff *skb)
*/
drop:
- kfree_skb(skb);
- ib_device_put(&rxe->ib_dev);
+ rxe_free_pkt(SKB_TO_PKT(skb));
}
/**
@@ -396,9 +417,5 @@ void rxe_rcv(struct sk_buff *skb)
return;
drop:
- if (pkt->qp)
- rxe_drop_ref(pkt->qp);
-
- kfree_skb(skb);
- ib_device_put(&rxe->ib_dev);
+ rxe_free_pkt(pkt);
}
@@ -98,11 +98,8 @@ static inline enum resp_states get_req(struct rxe_qp *qp,
struct sk_buff *skb;
if (qp->resp.state == QP_STATE_ERROR) {
- while ((skb = skb_dequeue(&qp->req_pkts))) {
- rxe_drop_ref(qp);
- kfree_skb(skb);
- ib_device_put(qp->ibqp.device);
- }
+ while ((skb = skb_dequeue(&qp->req_pkts)))
+ rxe_free_pkt(SKB_TO_PKT(skb));
/* go drain recv wr queue */
return RESPST_CHK_RESOURCE;
@@ -1020,9 +1017,7 @@ static enum resp_states cleanup(struct rxe_qp *qp,
if (pkt) {
skb = skb_dequeue(&qp->req_pkts);
- rxe_drop_ref(qp);
- kfree_skb(skb);
- ib_device_put(qp->ibqp.device);
+ rxe_free_pkt(SKB_TO_PKT(skb));
}
if (qp->resp.mr) {
@@ -1183,11 +1178,8 @@ static void rxe_drain_req_pkts(struct rxe_qp *qp, bool notify)
struct sk_buff *skb;
struct rxe_queue *q = qp->rq.queue;
- while ((skb = skb_dequeue(&qp->req_pkts))) {
- rxe_drop_ref(qp);
- kfree_skb(skb);
- ib_device_put(qp->ibqp.device);
- }
+ while ((skb = skb_dequeue(&qp->req_pkts)))
+ rxe_free_pkt(SKB_TO_PKT(skb));
if (notify)
return;
Currently on the receive path the rxe_pkt_info struct is stored in the skb->cb array. But this patch series requires extending it beyond 48 bytes and it is already at the limit. This patch places a pointer to the pkt info struct in skb->cb and allocates it separately. All instances of freeing the skb on the receive path are collected into rxe_free_pkt() calls which is extended to free the pkt info struct. In rxe_rcv_mcast_pkt() if skb_clone fails continue is replaced by break since we are out of memory and there is no point going on to the other mcast QPs. Signed-off-by: Bob Pearson <rpearsonhpe@gmail.com> --- drivers/infiniband/sw/rxe/rxe_comp.c | 20 +++------------- drivers/infiniband/sw/rxe/rxe_hdr.h | 13 ++++++++--- drivers/infiniband/sw/rxe/rxe_loc.h | 3 +++ drivers/infiniband/sw/rxe/rxe_net.c | 14 +++++++++-- drivers/infiniband/sw/rxe/rxe_recv.c | 35 +++++++++++++++++++++------- drivers/infiniband/sw/rxe/rxe_resp.c | 18 ++++---------- 6 files changed, 59 insertions(+), 44 deletions(-)