git: e29dccc64784 - main - iw_cxgbe: Fix qpid leak
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 15 Sep 2026 14:47:57 UTC
The branch main has been updated by jhb:
URL: https://cgit.FreeBSD.org/src/commit/?id=e29dccc64784bb572894c8b714ca212e38d8f8aa
commit e29dccc64784bb572894c8b714ca212e38d8f8aa
Author: Nirranjan Kirubaharan <nirranjan@chelsio.com>
AuthorDate: 2019-05-23 07:05:39 +0000
Commit: John Baldwin <jhb@FreeBSD.org>
CommitDate: 2026-09-15 14:22:40 +0000
iw_cxgbe: Fix qpid leak
Add await in destroy_qp() so that all references to qp are dereferenced
and qp is freed in destroy_qp() itself. This ensures freeing of all QPs
before invocation of dealloc_ucontext(), which prevents loss of in use
qpids stored in the ucontext.
Obtained from: Linux commit f70baa7ee3d1b5a9e66ac7549e31641a656f23c1
Sponsored by: Chelsio Communications
---
sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h | 4 ++--
sys/dev/cxgbe/iw_cxgbe/qp.c | 50 ++++++++++++++-------------------------
2 files changed, 20 insertions(+), 34 deletions(-)
diff --git a/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h b/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h
index 2112c4178591..ebe1b57f8660 100644
--- a/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h
+++ b/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h
@@ -461,13 +461,13 @@ struct c4iw_qp {
struct t4_wq wq;
spinlock_t lock;
struct mutex mutex;
- struct kref kref;
wait_queue_head_t wait;
struct timer_list timer;
int sq_sig_all;
- struct work_struct free_work;
struct c4iw_ucontext *ucontext;
struct c4iw_wr_wait *wr_waitp;
+ struct completion qp_rel_comp;
+ refcount_t qp_refcnt;
};
static inline struct c4iw_qp *to_c4iw_qp(struct ib_qp *ibqp)
diff --git a/sys/dev/cxgbe/iw_cxgbe/qp.c b/sys/dev/cxgbe/iw_cxgbe/qp.c
index 931a5be7c54e..9a5fc64c624b 100644
--- a/sys/dev/cxgbe/iw_cxgbe/qp.c
+++ b/sys/dev/cxgbe/iw_cxgbe/qp.c
@@ -632,44 +632,17 @@ static int build_inv_stag(union t4_wr *wqe, const struct ib_send_wr *wr,
return 0;
}
-static void free_qp_work(struct work_struct *work)
-{
- struct c4iw_ucontext *ucontext;
- struct c4iw_qp *qhp;
- struct c4iw_dev *rhp;
-
- qhp = container_of(work, struct c4iw_qp, free_work);
- ucontext = qhp->ucontext;
- rhp = qhp->rhp;
-
- CTR3(KTR_IW_CXGBE, "%s qhp %p ucontext %p", __func__,
- qhp, ucontext);
- destroy_qp(&rhp->rdev, &qhp->wq,
- ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
-
- c4iw_put_wr_wait(qhp->wr_waitp);
- kfree(qhp);
-}
-
-static void queue_qp_free(struct kref *kref)
-{
- struct c4iw_qp *qhp;
-
- qhp = container_of(kref, struct c4iw_qp, kref);
- CTR2(KTR_IW_CXGBE, "%s qhp %p", __func__, qhp);
- queue_work(qhp->rhp->rdev.free_workq, &qhp->free_work);
-}
-
void c4iw_qp_add_ref(struct ib_qp *qp)
{
CTR2(KTR_IW_CXGBE, "%s ib_qp %p", __func__, qp);
- kref_get(&to_c4iw_qp(qp)->kref);
+ refcount_inc(&to_c4iw_qp(qp)->qp_refcnt);
}
void c4iw_qp_rem_ref(struct ib_qp *qp)
{
CTR2(KTR_IW_CXGBE, "%s ib_qp %p", __func__, qp);
- kref_put(&to_c4iw_qp(qp)->kref, queue_qp_free);
+ if (refcount_dec_and_test(&to_c4iw_qp(qp)->qp_refcnt))
+ complete(&to_c4iw_qp(qp)->qp_rel_comp);
}
static int ib_to_fw_opcode(int ib_opcode)
@@ -1916,12 +1889,14 @@ out:
int c4iw_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
{
+ struct c4iw_ucontext *ucontext;
struct c4iw_dev *rhp;
struct c4iw_qp *qhp;
struct c4iw_qp_attributes attrs;
CTR2(KTR_IW_CXGBE, "%s ib_qp %p", __func__, ib_qp);
qhp = to_c4iw_qp(ib_qp);
+ ucontext = qhp->ucontext;
rhp = qhp->rhp;
attrs.next_state = C4IW_QP_STATE_ERROR;
@@ -1938,8 +1913,19 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
free_ird(rhp, qhp->attr.max_ird);
c4iw_qp_rem_ref(ib_qp);
+ wait_for_completion(&qhp->qp_rel_comp);
+
CTR3(KTR_IW_CXGBE, "%s ib_qp %p qpid 0x%0x", __func__, ib_qp,
qhp->wq.sq.qid);
+ CTR3(KTR_IW_CXGBE, "%s qhp %p ucontext %p", __func__,
+ qhp, ucontext);
+ destroy_qp(&rhp->rdev, &qhp->wq,
+ ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
+
+ c4iw_put_wr_wait(qhp->wr_waitp);
+
+ kfree(qhp);
+
return 0;
}
@@ -2044,8 +2030,8 @@ c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
spin_lock_init(&qhp->lock);
mutex_init(&qhp->mutex);
init_waitqueue_head(&qhp->wait);
- kref_init(&qhp->kref);
- INIT_WORK(&qhp->free_work, free_qp_work);
+ init_completion(&qhp->qp_rel_comp);
+ refcount_set(&qhp->qp_refcnt, 1);
ret = xa_insert_irq(&rhp->qps, qhp->wq.sq.qid, qhp, GFP_KERNEL);
if (ret)