iw_cxgb4: handle fw reply timeouts
Subsystems (2)
cover iw_cxgb4: handle fw reply timeouts
For messages sent from the host to fw that solicit a reply from fw, the c4iw_wr_wait struct pointer is passed in the host->fw message, and included in the fw->host fw6_msg reply. This allows the sender to wait until the reply is received, and the code processing the ingress reply to wake up the sender.
If c4iw_wait_for_reply() times out, however, we need to keep the c4iw_wr_wait object around in case the reply eventually does arrive. Otherwise we have touch-after-free bugs in the wake_up paths.
This series refactors the c4iw_wait_wr users and the wait API to handle this case. The first 4 patches change the users to allocate the wait object vs using it locally on the stack, and the 5th patch implmements the new kref for the wait objects.
Steve Wise (5):
iw_cxgb4: allocate wait object for each memory object
iw_cxgb4: allocate wait object for each cq object
iw_cxgb4: allocate wait object for each qp object
iw_cxgb4: allocate wait object for each ep object
iw_cxgb4: add referencing to wait objects
drivers/infiniband/hw/cxgb4/cm.c | 40 +++--- drivers/infiniband/hw/cxgb4/cq.c | 69 +++++----- drivers/infiniband/hw/cxgb4/device.c | 21 +++ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 66 ++++++++- drivers/infiniband/hw/cxgb4/mem.c | 242 ++++++++++++++++++++------------- drivers/infiniband/hw/cxgb4/qp.c | 82 +++++------ 6 files changed, 330 insertions(+), 190 deletions(-)
Signature · 6 lines
1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): cover.1506545745.git.swise-7bPotxP6k4+P2YhJcF5u+vpXobYPEAuW@public.gmane.org
PATCH 1/5 iw_cxgb4: allocate wait object for each memory object
Remove the local stack allocated c4iw_wr_wait object in preparation for correctly handling timeouts.
Also refactored some code to simplify it and make errpath unwinding more readable.
--- drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 2 + drivers/infiniband/hw/cxgb4/mem.c | 228 ++++++++++++++++++++------------- 2 files changed, 141 insertions(+), 89 deletions(-)
drivers/infiniband/hw/cxgb4/iw_cxgb4.h +2 -0
@@ -394,6 +394,7 @@ struct c4iw_mr {dma_addr_t mpl_addr;u32 max_mpl_len;u32 mpl_len; +struct c4iw_wr_wait *wr_waitp; };static inline struct c4iw_mr *to_c4iw_mr (struct ib_mr *ibmr)
@@ -407,6 +408,7 @@ struct c4iw_mw {struct sk_buff *dereg_skb;u64 kva;struct tpt_attributes attr; +struct c4iw_wr_wait *wr_waitp; };static inline struct c4iw_mw *to_c4iw_mw (struct ib_mw *ibmw)
drivers/infiniband/hw/cxgb4/mem.c +139 -89
514 lines not on this page · raw message
Signature · 6 lines
1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 2/5 iw_cxgb4: allocate wait object for each cq object
In reply to a message not in the archiveRemove the local stack allocated c4iw_wr_wait object in preparation for correctly handling timeouts.
Also cleaned up some error path unwind logic to make it more readable.
--- drivers/infiniband/hw/cxgb4/cq.c | 63 +++++++++++++++++++--------------- drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 1 + 2 files changed, 37 insertions(+), 27 deletions(-)
drivers/infiniband/hw/cxgb4/cq.c +36 -27
@@ -33,12 +33,12 @@#include "iw_cxgb4.h" static int destroy_cq (struct c4iw_rdev *rdev,struct t4_cq *cq, -struct c4iw_dev_ucontext *uctx,struct sk_buff *skb) +struct c4iw_dev_ucontext *uctx,struct sk_buff *skb, +struct c4iw_wr_wait *wr_waitp) {struct fw_ri_res_wr *res_wr;struct fw_ri_res *res;int wr_len; -struct c4iw_wr_wait wr_wait;int ret; wr_len =sizeof *res_wr +sizeof *res;
@@ -50,16 +50,16 @@ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,FW_RI_RES_WR_NRES_V (1 ) | FW_WR_COMPL_F); res_wr->len16_pkd =cpu_to_be32 (DIV_ROUND_UP (wr_len,16 )); - res_wr->cookie = (uintptr_t )&wr_wait; + res_wr->cookie = (uintptr_t )wr_waitp; res = res_wr->res; res->u.cq.restype =FW_RI_RES_TYPE_CQ ; res->u.cq.op =FW_RI_RES_OP_RESET ; res->u.cq.iqid =cpu_to_be32 (cq->cqid); -c4iw_init_wr_wait (&wr_wait); +c4iw_init_wr_wait (wr_waitp); ret =c4iw_ofld_send (rdev, skb);if (!ret) { - ret =c4iw_wait_for_reply (rdev, &wr_wait,0 ,0 , __func__); + ret =c4iw_wait_for_reply (rdev, wr_waitp,0 ,0 , __func__); }kfree (cq->sw_queue);
@@ -71,13 +71,13 @@ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, }static int create_cq (struct c4iw_rdev *rdev,struct t4_cq *cq, -struct c4iw_dev_ucontext *uctx) +struct c4iw_dev_ucontext *uctx, +struct c4iw_wr_wait *wr_waitp) {struct fw_ri_res_wr *res_wr;struct fw_ri_res *res;int wr_len;int user = (uctx != &rdev->uctx); -struct c4iw_wr_wait wr_wait;int ret;struct sk_buff *skb;
@@ -119,7 +119,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,FW_RI_RES_WR_NRES_V (1 ) | FW_WR_COMPL_F); res_wr->len16_pkd =cpu_to_be32 (DIV_ROUND_UP (wr_len,16 )); - res_wr->cookie = (uintptr_t )&wr_wait; + res_wr->cookie = (uintptr_t )wr_waitp; res = res_wr->res; res->u.cq.restype =FW_RI_RES_TYPE_CQ ; res->u.cq.op =FW_RI_RES_OP_WRITE ;
@@ -139,13 +139,13 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, res->u.cq.iqsize =cpu_to_be16 (cq->size); res->u.cq.iqaddr =cpu_to_be64 (cq->dma_addr); -c4iw_init_wr_wait (&wr_wait); +c4iw_init_wr_wait (wr_waitp); ret =c4iw_ofld_send (rdev, skb);if (ret) goto err4; -pr_debug ("wait_event wr_wait %p\n" , &wr_wait); - ret =c4iw_wait_for_reply (rdev, &wr_wait,0 ,0 , __func__); +pr_debug ("wait_event wr_wait %p\n" , wr_waitp); + ret =c4iw_wait_for_reply (rdev, wr_waitp,0 ,0 , __func__);if (ret) goto err4;
@@ -868,8 +868,8 @@ int c4iw_destroy_cq(struct ib_cq *ib_cq) : NULL;destroy_cq (&chp->rhp->rdev, &chp->cq, ucontext ? &ucontext->uctx : &chp->cq.rdev->uctx, - chp->destroy_skb); - chp->destroy_skb =NULL ; + chp->destroy_skb, chp->wr_waitp); +kfree (chp->wr_waitp);kfree (chp);return 0 ; }
@@ -901,12 +901,18 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, chp =kzalloc (sizeof (*chp),GFP_KERNEL );if (!chp)return ERR_PTR (-ENOMEM ); + chp->wr_waitp =kzalloc (sizeof (*chp->wr_waitp),GFP_KERNEL ); +if (!chp->wr_waitp) { + ret = -ENOMEM ; + goto err_free_chp; + } +c4iw_init_wr_wait (chp->wr_waitp); wr_len =sizeof (struct fw_ri_res_wr ) +sizeof (struct fw_ri_res ); chp->destroy_skb =alloc_skb (wr_len,GFP_KERNEL );if (!chp->destroy_skb) { ret = -ENOMEM ; - goto err1; + goto err_free_wr_wait; }if (ib_context)
@@ -947,9 +953,10 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, chp->cq.vector = vector; ret =create_cq (&rhp->rdev, &chp->cq, - ucontext ? &ucontext->uctx : &rhp->rdev.uctx); + ucontext ? &ucontext->uctx : &rhp->rdev.uctx, + chp->wr_waitp);if (ret) - goto err2; + goto err_free_skb; chp->rhp = rhp; chp->cq.size--;/* status page */
@@ -960,16 +967,16 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,init_waitqueue_head (&chp->wait); ret =insert_handle (rhp, &rhp->cqidr, chp, chp->cq.cqid);if (ret) - goto err3; + goto err_destroy_cq;if (ucontext) { ret = -ENOMEM ; mm =kmalloc (sizeof *mm,GFP_KERNEL );if (!mm) - goto err4; + goto err_remove_handle; mm2 =kmalloc (sizeof *mm2,GFP_KERNEL );if (!mm2) - goto err5; + goto err_free_mm; uresp.qid_mask = rhp->rdev.cqmask; uresp.cqid = chp->cq.cqid;
@@ -984,7 +991,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, ret =ib_copy_to_udata (udata, &uresp,sizeof (uresp) -sizeof (uresp.reserved));if (ret) - goto err6; + goto err_free_mm2; mm->key = uresp.key; mm->addr =virt_to_phys (chp->cq.queue);
@@ -1000,19 +1007,21 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, chp->cq.cqid, chp, chp->cq.size, chp->cq.memsize, (unsigned long long)chp->cq.dma_addr);return &chp->ibcq; -err6: +err_free_mm2:kfree (mm2); -err5: +err_free_mm:kfree (mm); -err4: +err_remove_handle:remove_handle (rhp, &rhp->cqidr, chp->cq.cqid); -err3: +err_destroy_cq:destroy_cq (&chp->rhp->rdev, &chp->cq, ucontext ? &ucontext->uctx : &rhp->rdev.uctx, - chp->destroy_skb); -err2: + chp->destroy_skb, chp->wr_waitp); +err_free_skb:kfree_skb (chp->destroy_skb); -err1: +err_free_wr_wait: +kfree (chp->wr_waitp); +err_free_chp:kfree (chp);return ERR_PTR (ret); }
drivers/infiniband/hw/cxgb4/iw_cxgb4.h +1 -0
@@ -425,6 +425,7 @@ struct c4iw_cq {spinlock_t comp_handler_lock;atomic_t refcnt;wait_queue_head_t wait; +struct c4iw_wr_wait *wr_waitp; };static inline struct c4iw_cq *to_c4iw_cq (struct ib_cq *ibcq)
Signature · 6 lines
1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 3/5 iw_cxgb4: allocate wait object for each qp object
In reply to a message not in the archiveRemove the local stack allocated c4iw_wr_wait object in preparation for correctly handling timeouts.
Also cleaned up some error path unwind logic to make it more readable.
--- drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 1 + drivers/infiniband/hw/cxgb4/qp.c | 55 ++++++++++++++++++++-------------- 2 files changed, 34 insertions(+), 22 deletions(-)
drivers/infiniband/hw/cxgb4/iw_cxgb4.h +1 -0
@@ -487,6 +487,7 @@ struct c4iw_qp {int sq_sig_all;struct work_struct free_work;struct c4iw_ucontext *ucontext; +struct c4iw_wr_wait *wr_waitp; };static inline struct c4iw_qp *to_c4iw_qp (struct ib_qp *ibqp)
drivers/infiniband/hw/cxgb4/qp.c +33 -22
150 lines not on this page · raw message
Signature · 6 lines
1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 4/5 iw_cxgb4: allocate wait object for each ep object
In reply to a message not in the archiveRemove the embedded c4iw_wr_wait object in preparation for correctly handling timeouts.
--- drivers/infiniband/hw/cxgb4/cm.c | 38 ++++++++++++++++++++-------------- drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 2 +- drivers/infiniband/hw/cxgb4/qp.c | 8 +++---- 3 files changed, 28 insertions(+), 20 deletions(-)
drivers/infiniband/hw/cxgb4/cm.c +23 -15
@@ -318,11 +318,18 @@ static void *alloc_ep(int size, gfp_t gfp) epc =kzalloc (size, gfp);if (epc) { + epc->wr_waitp =kzalloc (sizeof (*epc->wr_waitp), gfp); +if (!epc->wr_waitp) { +kfree (epc); + epc =NULL ; + goto out; + }kref_init (&epc->kref);mutex_init (&epc->mutex); -c4iw_init_wr_wait (&epc->wr_wait); +c4iw_init_wr_wait (epc->wr_waitp); }pr_debug ("alloc ep %p\n" , epc); +out:return epc; }
@@ -407,6 +414,7 @@ void _c4iw_free_ep(struct kref *kref) }if (!skb_queue_empty (&ep->com.ep_skb_list))skb_queue_purge (&ep->com.ep_skb_list); +kfree (ep->com.wr_waitp);kfree (ep); }
@@ -1872,7 +1880,7 @@ static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb)mutex_lock (&ep->com.mutex);switch (ep->com.state) {case ABORTING : -c4iw_wake_up (&ep->com.wr_wait, -ECONNRESET ); +c4iw_wake_up (ep->com.wr_waitp, -ECONNRESET );__state_set (&ep->com,DEAD ); release =1 ;break ;
@@ -2100,7 +2108,7 @@ static int c4iw_reconnect(struct c4iw_ep *ep)pr_debug ("qp %p cm_id %p\n" , ep->com.qp, ep->com.cm_id);init_timer (&ep->timer); -c4iw_init_wr_wait (&ep->com.wr_wait); +c4iw_init_wr_wait (ep->com.wr_waitp);/* When MPA revision is different on nodes, the node with MPA_rev=2 * tries to reconnect with MPA_rev 1 for the same EP through
@@ -2319,7 +2327,7 @@ static int pass_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb) }pr_debug ("ep %p status %d error %d\n" , ep, rpl->status,status2errno (rpl->status)); -c4iw_wake_up (&ep->com.wr_wait,status2errno (rpl->status)); +c4iw_wake_up (ep->com.wr_waitp,status2errno (rpl->status));c4iw_put_ep (&ep->com); out:return 0 ;
@@ -2336,7 +2344,7 @@ static int close_listsrv_rpl(struct c4iw_dev *dev, struct sk_buff *skb) goto out; }pr_debug ("ep %p\n" , ep); -c4iw_wake_up (&ep->com.wr_wait,status2errno (rpl->status)); +c4iw_wake_up (ep->com.wr_waitp,status2errno (rpl->status));c4iw_put_ep (&ep->com); out:return 0 ;
@@ -2671,12 +2679,12 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)*/ __state_set (&ep->com,CLOSING );pr_debug ("waking up ep %p tid %u\n" , ep, ep->hwtid); -c4iw_wake_up (&ep->com.wr_wait, -ECONNRESET ); +c4iw_wake_up (ep->com.wr_waitp, -ECONNRESET );break ;case MPA_REP_SENT :__state_set (&ep->com,CLOSING );pr_debug ("waking up ep %p tid %u\n" , ep, ep->hwtid); -c4iw_wake_up (&ep->com.wr_wait, -ECONNRESET ); +c4iw_wake_up (ep->com.wr_waitp, -ECONNRESET );break ;case FPDU_MODE :start_ep_timer (ep);
@@ -2758,7 +2766,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)* MPA_REQ_SENT */ if (ep->com.state !=MPA_REQ_SENT ) -c4iw_wake_up (&ep->com.wr_wait, -ECONNRESET ); +c4iw_wake_up (ep->com.wr_waitp, -ECONNRESET );mutex_lock (&ep->com.mutex);switch (ep->com.state) {
@@ -3346,14 +3354,14 @@ static int create_server6(struct c4iw_dev *dev, struct c4iw_listen_ep *ep)if (err)return err; } -c4iw_init_wr_wait (&ep->com.wr_wait); +c4iw_init_wr_wait (ep->com.wr_waitp); err =cxgb4_create_server6 (ep->com.dev->rdev.lldi.ports[0 ], ep->stid, &sin6->sin6_addr, sin6->sin6_port, ep->com.dev->rdev.lldi.rxq_ids[0 ]);if (!err) err =c4iw_wait_for_reply (&ep->com.dev->rdev, - &ep->com.wr_wait, + ep->com.wr_waitp,0 ,0 , __func__);else if (err >0 ) err =net_xmit_errno (err);
@@ -3389,13 +3397,13 @@ static int create_server4(struct c4iw_dev *dev, struct c4iw_listen_ep *ep) } }while (err == -EBUSY ); }else { -c4iw_init_wr_wait (&ep->com.wr_wait); +c4iw_init_wr_wait (ep->com.wr_waitp); err =cxgb4_create_server (ep->com.dev->rdev.lldi.ports[0 ], ep->stid, sin->sin_addr.s_addr, sin->sin_port,0 , ep->com.dev->rdev.lldi.rxq_ids[0 ]);if (!err) err =c4iw_wait_for_reply (&ep->com.dev->rdev, - &ep->com.wr_wait, + ep->com.wr_waitp,0 ,0 , __func__);else if (err >0 ) err =net_xmit_errno (err);
@@ -3487,13 +3495,13 @@ int c4iw_destroy_listen(struct iw_cm_id *cm_id) ep->com.dev->rdev.lldi.rxq_ids[0], 0); }else {struct sockaddr_in6 *sin6; -c4iw_init_wr_wait (&ep->com.wr_wait); +c4iw_init_wr_wait (ep->com.wr_waitp); err =cxgb4_remove_server ( ep->com.dev->rdev.lldi.ports[0 ], ep->stid, ep->com.dev->rdev.lldi.rxq_ids[0 ],0 );if (err) goto done; - err =c4iw_wait_for_reply (&ep->com.dev->rdev, &ep->com.wr_wait, + err =c4iw_wait_for_reply (&ep->com.dev->rdev, ep->com.wr_waitp,0 ,0 , __func__); sin6 = (struct sockaddr_in6 *)&ep->com.local_addr; cxgb4_clip_release(ep->com.dev->rdev.lldi.ports[0],
@@ -4216,7 +4224,7 @@ static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb) }pr_debug ("ep %p tid %u state %u\n" , ep, ep->hwtid, ep->com.state); -c4iw_wake_up (&ep->com.wr_wait, -ECONNRESET ); +c4iw_wake_up (ep->com.wr_waitp, -ECONNRESET ); out:sched (dev, skb);return 0 ;
drivers/infiniband/hw/cxgb4/iw_cxgb4.h +1 -1
@@ -842,7 +842,7 @@ struct c4iw_ep_common {struct mutex mutex;struct sockaddr_storage local_addr;struct sockaddr_storage remote_addr; -struct c4iw_wr_wait wr_wait; +struct c4iw_wr_wait *wr_waitp;unsigned long flags;unsigned long history; };
drivers/infiniband/hw/cxgb4/qp.c +4 -4
@@ -1355,14 +1355,14 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp, wqe->flowid_len16 =cpu_to_be32 (FW_WR_FLOWID_V (ep->hwtid) |FW_WR_LEN16_V (DIV_ROUND_UP (sizeof (*wqe),16 ))); - wqe->cookie = (uintptr_t )&ep->com.wr_wait; + wqe->cookie = (uintptr_t )ep->com.wr_waitp; wqe->u.fini.type =FW_RI_TYPE_FINI ; ret =c4iw_ofld_send (&rhp->rdev, skb);if (ret) goto out; - ret =c4iw_wait_for_reply (&rhp->rdev, &ep->com.wr_wait, qhp->ep->hwtid, + ret =c4iw_wait_for_reply (&rhp->rdev, ep->com.wr_waitp, qhp->ep->hwtid, qhp->wq.sq.qid, __func__); out:pr_debug ("ret %d\n" , ret);
@@ -1425,7 +1425,7 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)FW_WR_FLOWID_V (qhp->ep->hwtid) | FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16))); - wqe->cookie = (uintptr_t )&qhp->ep->com.wr_wait; + wqe->cookie = (uintptr_t )qhp->ep->com.wr_waitp; wqe->u.init.type =FW_RI_TYPE_INIT ; wqe->u.init.mpareqbit_p2ptype =
@@ -1466,7 +1466,7 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)if (ret) goto err1; - ret =c4iw_wait_for_reply (&rhp->rdev, &qhp->ep->com.wr_wait, + ret =c4iw_wait_for_reply (&rhp->rdev, qhp->ep->com.wr_waitp, qhp->ep->hwtid, qhp->wq.sq.qid, __func__);if (!ret) goto out;
Signature · 6 lines
1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 5/5 iw_cxgb4: add referencing to wait objects
In reply to a message not in the archiveFor messages sent from the host to fw that solicit a reply from fw, the c4iw_wr_wait struct pointer is passed in the host->fw message, and included in the fw->host fw6_msg reply. This allows the sender to wait until the reply is received, and the code processing the ingress reply to wake up the sender.
If c4iw_wait_for_reply() times out, however, we need to keep the c4iw_wr_wait object around in case the reply eventually does arrive. Otherwise we have touch-after-free bugs in the wake_up paths.
This was hit due to a bad kernel driver that blocked ingress processing of cxgb4 for a long time, causing iw_cxgb4 timeouts, but eventually resuming ingress processing and thus hitting the touch-after-free bug.
So I want to fix iw_cxgb4 such that we'll at least keep the wait object around until the reply comes. If it never comes we leak a small amount of memory, but if it does come late, we won't potentially crash the system.
So add a kref struct in the c4iw_wr_wait struct, and take a reference before sending a message to FW that will generate a FW6 reply. And remove the reference (and potentially free the wait object) when the reply is processed.
The ep code also uses the wr_wait for non FW6 CPL messages and doesn't embed the c4iw_wr_wait object in the message sent to firmware. So for those cases we add c4iw_wake_up_noref().
The mr/mw, cq, and qp object create/destroy paths do need this reference logic. For these paths, c4iw_ref_send_wait() is introduced to take the wr_wait reference, send the msg to fw, and then wait for the reply.
So going forward, iw_cxgb4 either uses c4iw_ofld_send(), c4iw_wait_for_reply() and c4iw_wake_up_noref() like is done in the some of the endpoint logic, or c4iw_ref_send_wait() and c4iw_wake_up_deref() (formerly c4iw_wake_up()) when sending messages with the c4iw_wr_wait object pointer embedded in the message and resulting FW6 reply.
--- drivers/infiniband/hw/cxgb4/cm.c | 20 ++++++------ drivers/infiniband/hw/cxgb4/cq.c | 18 +++------- drivers/infiniband/hw/cxgb4/device.c | 21 ++++++++++++ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 60 ++++++++++++++++++++++++++++++++-- drivers/infiniband/hw/cxgb4/mem.c | 38 +++++++++++---------- drivers/infiniband/hw/cxgb4/qp.c | 31 ++++++------------ 6 files changed, 123 insertions(+), 65 deletions(-)
drivers/infiniband/hw/cxgb4/cm.c +10 -10
@@ -318,7 +318,7 @@ static void *alloc_ep(int size, gfp_t gfp) epc =kzalloc (size, gfp);if (epc) { - epc->wr_waitp =kzalloc (sizeof (*epc->wr_waitp), gfp); + epc->wr_waitp =c4iw_alloc_wr_wait (gfp);if (!epc->wr_waitp) {kfree (epc); epc =NULL ;
@@ -414,7 +414,7 @@ void _c4iw_free_ep(struct kref *kref) }if (!skb_queue_empty (&ep->com.ep_skb_list))skb_queue_purge (&ep->com.ep_skb_list); -kfree (ep->com.wr_waitp); +c4iw_put_wr_wait (ep->com.wr_waitp);kfree (ep); }
@@ -1880,7 +1880,7 @@ static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb)mutex_lock (&ep->com.mutex);switch (ep->com.state) {case ABORTING : -c4iw_wake_up (ep->com.wr_waitp, -ECONNRESET ); +c4iw_wake_up_noref (ep->com.wr_waitp, -ECONNRESET );__state_set (&ep->com,DEAD ); release =1 ;break ;
@@ -2327,7 +2327,7 @@ static int pass_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb) }pr_debug ("ep %p status %d error %d\n" , ep, rpl->status,status2errno (rpl->status)); -c4iw_wake_up (ep->com.wr_waitp,status2errno (rpl->status)); +c4iw_wake_up_noref (ep->com.wr_waitp,status2errno (rpl->status));c4iw_put_ep (&ep->com); out:return 0 ;
@@ -2344,7 +2344,7 @@ static int close_listsrv_rpl(struct c4iw_dev *dev, struct sk_buff *skb) goto out; }pr_debug ("ep %p\n" , ep); -c4iw_wake_up (ep->com.wr_waitp,status2errno (rpl->status)); +c4iw_wake_up_noref (ep->com.wr_waitp,status2errno (rpl->status));c4iw_put_ep (&ep->com); out:return 0 ;
@@ -2679,12 +2679,12 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)*/ __state_set (&ep->com,CLOSING );pr_debug ("waking up ep %p tid %u\n" , ep, ep->hwtid); -c4iw_wake_up (ep->com.wr_waitp, -ECONNRESET ); +c4iw_wake_up_noref (ep->com.wr_waitp, -ECONNRESET );break ;case MPA_REP_SENT :__state_set (&ep->com,CLOSING );pr_debug ("waking up ep %p tid %u\n" , ep, ep->hwtid); -c4iw_wake_up (ep->com.wr_waitp, -ECONNRESET ); +c4iw_wake_up_noref (ep->com.wr_waitp, -ECONNRESET );break ;case FPDU_MODE :start_ep_timer (ep);
@@ -2766,7 +2766,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)* MPA_REQ_SENT */ if (ep->com.state !=MPA_REQ_SENT ) -c4iw_wake_up (ep->com.wr_waitp, -ECONNRESET ); +c4iw_wake_up_noref (ep->com.wr_waitp, -ECONNRESET );mutex_lock (&ep->com.mutex);switch (ep->com.state) {
@@ -4187,7 +4187,7 @@ static int fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb) wr_waitp = (struct c4iw_wr_wait *)(__force unsigned long ) rpl->data[1 ];pr_debug ("wr_waitp %p ret %u\n" , wr_waitp, ret);if (wr_waitp) -c4iw_wake_up (wr_waitp, ret ? -ret :0 ); +c4iw_wake_up_deref (wr_waitp, ret ? -ret :0 );kfree_skb (skb);break ;case FW6_TYPE_CQE :
@@ -4224,7 +4224,7 @@ static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb) }pr_debug ("ep %p tid %u state %u\n" , ep, ep->hwtid, ep->com.state); -c4iw_wake_up (ep->com.wr_waitp, -ECONNRESET ); +c4iw_wake_up_noref (ep->com.wr_waitp, -ECONNRESET ); out:sched (dev, skb);return 0 ;
drivers/infiniband/hw/cxgb4/cq.c +5 -13
@@ -57,10 +57,7 @@ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, res->u.cq.iqid =cpu_to_be32 (cq->cqid);c4iw_init_wr_wait (wr_waitp); - ret =c4iw_ofld_send (rdev, skb); -if (!ret) { - ret =c4iw_wait_for_reply (rdev, wr_waitp,0 ,0 , __func__); - } + ret =c4iw_ref_send_wait (rdev, skb, wr_waitp,0 ,0 , __func__);kfree (cq->sw_queue); dma_free_coherent(&(rdev->lldi.pdev->dev),
@@ -140,12 +137,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, res->u.cq.iqaddr =cpu_to_be64 (cq->dma_addr);c4iw_init_wr_wait (wr_waitp); - - ret =c4iw_ofld_send (rdev, skb); -if (ret) - goto err4; -pr_debug ("wait_event wr_wait %p\n" , wr_waitp); - ret =c4iw_wait_for_reply (rdev, wr_waitp,0 ,0 , __func__); + ret =c4iw_ref_send_wait (rdev, skb, wr_waitp,0 ,0 , __func__);if (ret) goto err4;
@@ -869,7 +861,7 @@ int c4iw_destroy_cq(struct ib_cq *ib_cq)destroy_cq (&chp->rhp->rdev, &chp->cq, ucontext ? &ucontext->uctx : &chp->cq.rdev->uctx, chp->destroy_skb, chp->wr_waitp); -kfree (chp->wr_waitp); +c4iw_put_wr_wait (chp->wr_waitp);kfree (chp);return 0 ; }
@@ -901,7 +893,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, chp =kzalloc (sizeof (*chp),GFP_KERNEL );if (!chp)return ERR_PTR (-ENOMEM ); - chp->wr_waitp =kzalloc (sizeof (*chp->wr_waitp),GFP_KERNEL ); + chp->wr_waitp =c4iw_alloc_wr_wait (GFP_KERNEL );if (!chp->wr_waitp) { ret = -ENOMEM ; goto err_free_chp;
@@ -1020,7 +1012,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, err_free_skb:kfree_skb (chp->destroy_skb); err_free_wr_wait: -kfree (chp->wr_waitp); +c4iw_put_wr_wait (chp->wr_waitp); err_free_chp:kfree (chp);return ERR_PTR (ret);
drivers/infiniband/hw/cxgb4/device.c +21 -0
@@ -1518,6 +1518,27 @@ static int c4iw_uld_control(void *handle, enum cxgb4_control control, ...) .control = c4iw_uld_control, }; +void _c4iw_free_wr_wait (struct kref *kref) +{ +struct c4iw_wr_wait *wr_waitp; + + wr_waitp = container_of(kref, struct c4iw_wr_wait, kref); +pr_debug ("Free wr_wait %p\n" , wr_waitp); +kfree (wr_waitp); +} + +struct c4iw_wr_wait *c4iw_alloc_wr_wait (gfp_t gfp) +{ +struct c4iw_wr_wait *wr_waitp; + + wr_waitp =kzalloc (sizeof (*wr_waitp), gfp); +if (wr_waitp) { +kref_init (&wr_waitp->kref); +pr_debug ("wr_wait %p\n" , wr_waitp); + } +return wr_waitp; +} +static int __init c4iw_init_module (void ) {int err;
drivers/infiniband/hw/cxgb4/iw_cxgb4.h +57 -3
101 lines not on this page · raw message
drivers/infiniband/hw/cxgb4/mem.c +20 -18
@@ -100,11 +100,10 @@ static int _c4iw_write_mem_dma_aligned(struct c4iw_rdev *rdev, u32 addr, sgl->len0 =cpu_to_be32 (len); sgl->addr0 =cpu_to_be64 (data); - ret =c4iw_ofld_send (rdev, skb); -if (ret) -return ret;if (wr_waitp) - ret =c4iw_wait_for_reply (rdev, wr_waitp,0 ,0 , __func__); + ret =c4iw_ref_send_wait (rdev, skb, wr_waitp,0 ,0 , __func__); +else + ret =c4iw_ofld_send (rdev, skb);return ret; }
@@ -173,14 +172,17 @@ static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len,if (copy_len %T4_ULPTX_MIN_IO )memset (to_dp + copy_len,0 ,T4_ULPTX_MIN_IO - (copy_len %T4_ULPTX_MIN_IO )); - ret =c4iw_ofld_send (rdev, skb); - skb =NULL ; +if (i == (num_wqe-1 )) + ret =c4iw_ref_send_wait (rdev, skb, wr_waitp,0 ,0 , + __func__); +else + ret =c4iw_ofld_send (rdev, skb);if (ret) -return ret; +break ; + skb =NULL ; len -=C4IW_MAX_INLINE_SIZE ; } - ret =c4iw_wait_for_reply (rdev, wr_waitp,0 ,0 , __func__);return ret; }
@@ -447,7 +449,7 @@ struct ib_mr *c4iw_get_dma_mr(struct ib_pd *pd, int acc) mhp =kzalloc (sizeof (*mhp),GFP_KERNEL );if (!mhp)return ERR_PTR (-ENOMEM ); - mhp->wr_waitp =kzalloc (sizeof (*mhp->wr_waitp),GFP_KERNEL ); + mhp->wr_waitp =c4iw_alloc_wr_wait (GFP_KERNEL );if (!mhp->wr_waitp) { ret = -ENOMEM ; goto err_free_mhp;
@@ -485,7 +487,7 @@ struct ib_mr *c4iw_get_dma_mr(struct ib_pd *pd, int acc)dereg_mem (&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size, mhp->attr.pbl_addr, mhp->dereg_skb, mhp->wr_waitp); err_free_wr_wait: -kfree (mhp->wr_waitp); +c4iw_put_wr_wait (mhp->wr_waitp); err_free_skb:kfree_skb (mhp->dereg_skb); err_free_mhp:
@@ -522,7 +524,7 @@ struct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, mhp =kzalloc (sizeof (*mhp),GFP_KERNEL );if (!mhp)return ERR_PTR (-ENOMEM ); - mhp->wr_waitp =kzalloc (sizeof (*mhp->wr_waitp),GFP_KERNEL ); + mhp->wr_waitp =c4iw_alloc_wr_wait (GFP_KERNEL );if (!mhp->wr_waitp) goto err_free_mhp;
@@ -600,7 +602,7 @@ struct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, err_free_skb:kfree_skb (mhp->dereg_skb); err_free_wr_wait: -kfree (mhp->wr_waitp); +c4iw_put_wr_wait (mhp->wr_waitp); err_free_mhp:kfree (mhp);return ERR_PTR (err);
@@ -625,7 +627,7 @@ struct ib_mw *c4iw_alloc_mw(struct ib_pd *pd, enum ib_mw_type type,if (!mhp)return ERR_PTR (-ENOMEM ); - mhp->wr_waitp =kzalloc (sizeof (*mhp->wr_waitp),GFP_KERNEL ); + mhp->wr_waitp =c4iw_alloc_wr_wait (GFP_KERNEL );if (!mhp->wr_waitp) { ret = -ENOMEM ; goto free_mhp;
@@ -659,7 +661,7 @@ struct ib_mw *c4iw_alloc_mw(struct ib_pd *pd, enum ib_mw_type type, free_skb:kfree_skb (mhp->dereg_skb); free_wr_wait: -kfree (mhp->wr_waitp); +c4iw_put_wr_wait (mhp->wr_waitp); free_mhp:kfree (mhp);return ERR_PTR (ret);
@@ -678,7 +680,7 @@ int c4iw_dealloc_mw(struct ib_mw *mw)deallocate_window (&rhp->rdev, mhp->attr.stag, mhp->dereg_skb, mhp->wr_waitp);kfree_skb (mhp->dereg_skb); -kfree (mhp->wr_waitp); +c4iw_put_wr_wait (mhp->wr_waitp);kfree (mhp);pr_debug ("ib_mw %p mmid 0x%x ptr %p\n" , mw, mmid, mhp);return 0 ;
@@ -710,7 +712,7 @@ struct ib_mr *c4iw_alloc_mr(struct ib_pd *pd, goto err; } - mhp->wr_waitp =kzalloc (sizeof (*mhp->wr_waitp),GFP_KERNEL ); + mhp->wr_waitp =c4iw_alloc_wr_wait (GFP_KERNEL );if (!mhp->wr_waitp) { ret = -ENOMEM ; goto err_free_mhp;
@@ -758,7 +760,7 @@ struct ib_mr *c4iw_alloc_mr(struct ib_pd *pd,dma_free_coherent (&mhp->rhp->rdev.lldi.pdev->dev, mhp->max_mpl_len, mhp->mpl, mhp->mpl_addr); err_free_wr_wait: -kfree (mhp->wr_waitp); +c4iw_put_wr_wait (mhp->wr_waitp); err_free_mhp:kfree (mhp); err:
@@ -812,7 +814,7 @@ int c4iw_dereg_mr(struct ib_mr *ib_mr)if (mhp->umem)ib_umem_release (mhp->umem);pr_debug ("mmid 0x%x ptr %p\n" , mmid, mhp); -kfree (mhp->wr_waitp); +c4iw_put_wr_wait (mhp->wr_waitp);kfree (mhp);return 0 ; }
drivers/infiniband/hw/cxgb4/qp.c +10 -21
@@ -353,11 +353,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, res->u.sqrq.eqaddr =cpu_to_be64 (wq->rq.dma_addr);c4iw_init_wr_wait (wr_waitp); - - ret =c4iw_ofld_send (rdev, skb); -if (ret) - goto free_dma; - ret =c4iw_wait_for_reply (rdev, wr_waitp,0 , wq->sq.qid, __func__); + ret =c4iw_ref_send_wait (rdev, skb, wr_waitp,0 , wq->sq.qid, __func__);if (ret) goto free_dma;
@@ -730,7 +726,7 @@ static void free_qp_work(struct work_struct *work)if (ucontext)c4iw_put_ucontext (ucontext); -kfree (qhp->wr_waitp); +c4iw_put_wr_wait (qhp->wr_waitp);kfree (qhp); }
@@ -1358,13 +1354,10 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp, wqe->cookie = (uintptr_t )ep->com.wr_waitp; wqe->u.fini.type =FW_RI_TYPE_FINI ; - ret =c4iw_ofld_send (&rhp->rdev, skb); -if (ret) - goto out; - ret =c4iw_wait_for_reply (&rhp->rdev, ep->com.wr_waitp, qhp->ep->hwtid, - qhp->wq.sq.qid, __func__); -out: + ret =c4iw_ref_send_wait (&rhp->rdev, skb, ep->com.wr_waitp, + qhp->ep->hwtid, qhp->wq.sq.qid, __func__); +pr_debug ("ret %d\n" , ret);return ret; }
@@ -1462,15 +1455,11 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)if (qhp->attr.mpa_attr.initiator)build_rtr_msg (qhp->attr.mpa_attr.p2p_type, &wqe->u.init); - ret =c4iw_ofld_send (&rhp->rdev, skb); -if (ret) - goto err1; - - ret =c4iw_wait_for_reply (&rhp->rdev, qhp->ep->com.wr_waitp, - qhp->ep->hwtid, qhp->wq.sq.qid, __func__); + ret =c4iw_ref_send_wait (&rhp->rdev, skb, qhp->ep->com.wr_waitp, + qhp->ep->hwtid, qhp->wq.sq.qid, __func__);if (!ret) goto out; -err1: +free_ird (rhp, qhp->attr.max_ird); out:pr_debug ("ret %d\n" , ret);
@@ -1796,7 +1785,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,if (!qhp)return ERR_PTR (-ENOMEM ); - qhp->wr_waitp =kzalloc (sizeof (*qhp),GFP_KERNEL ); + qhp->wr_waitp =c4iw_alloc_wr_wait (GFP_KERNEL );if (!qhp->wr_waitp) { ret = -ENOMEM ; goto err_free_qhp;
@@ -1963,7 +1952,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,destroy_qp (&rhp->rdev, &qhp->wq, ucontext ? &ucontext->uctx : &rhp->rdev.uctx); err_free_wr_wait: -kfree (qhp->wr_waitp); +c4iw_put_wr_wait (qhp->wr_waitp); err_free_qhp:kfree (qhp);return ERR_PTR (ret);
Signature · 6 lines
1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 27 lines · Steve Wise
For messages sent from the host to fw that solicit a reply from fw, the
c4iw_wr_waitstruct pointer is passed in thehost->fwmessage, and
included in thefw->hostfw6_msgreply. This allows the sender to wait
until the reply is received, and the code processing the ingress reply
to wake up the sender.If
c4iw_wait_for_reply()times out, however, we need to keep thec4iw_wr_waitobject around in case the reply eventually does arrive. Otherwise we have touch-after-free bugs in thewake_uppaths.This series refactors the
c4iw_wait_wrusers and the wait API to handle
this case. The first 4 patches change the users to allocate the wait object vs using it locally on the stack, and the 5th patch implmements the
new kref for the wait objects.Steve Wise (5):
iw_cxgb4: allocate wait object for each memory object
iw_cxgb4: allocate wait object for each cq object
iw_cxgb4: allocate wait object for each qp object
iw_cxgb4: allocate wait object for each ep object
iw_cxgb4: add referencing to wait objects
Quoted 8 lines
drivers/infiniband/hw/cxgb4/cm.c | 40 +++--- drivers/infiniband/hw/cxgb4/cq.c | 69 +++++----- drivers/infiniband/hw/cxgb4/device.c | 21 +++ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 66 ++++++++- drivers/infiniband/hw/cxgb4/mem.c | 242 ++++++++++++++++++++--- ---------- drivers/infiniband/hw/cxgb4/qp.c | 82 +++++------ 6 files changed, 330 insertions(+), 190 deletions(-)
Thanks Steve, applied.
Signature · 8 lines
Doug Ledford <[email protected]> GPG KeyID: B826A3330E572FDD Key fingerprint = AE6B 1BDA 122B 23B4 265B 1274 B826 A333 0E57 2FDD -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html