iw_cxgb4: add referencing to wait objects
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 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. Signed-off-by: Steve Wise <swise@opengridcomputing.com> Signed-off-by: Doug Ledford <dledford@redhat.com>
这个提交包含在:
@@ -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 @@ err_destroy_cq:
|
||||
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);
|
||||
|
在新工单中引用
屏蔽一个用户