Linux RDMA and InfiniBand development
 help / color / mirror / Atom feed
From: Selvin Xavier <selvin.xavier@broadcom.com>
To: leon@kernel.org, jgg@ziepe.ca
Cc: linux-rdma@vger.kernel.org, andrew.gospodarek@broadcom.com,
	kalesh-anakkur.purayil@broadcom.com,
	sriharsha.basavapatna@broadcom.com, alhouseenyousef@gmail.com,
	Selvin Xavier <selvin.xavier@broadcom.com>
Subject: [PATCH for-next v3 2/4] RDMA/bnxt_re: Defer toggle page free to rdma_user_mmap_entry teardown
Date: Mon, 13 Jul 2026 06:58:28 -0700	[thread overview]
Message-ID: <20260713135830.1934471-3-selvin.xavier@broadcom.com> (raw)
In-Reply-To: <20260713135830.1934471-1-selvin.xavier@broadcom.com>

Fix the page lifetime by making the rdma_user_mmap_entry the sole owner
of the toggle page allocation. Creating the rdma_user_mmap_entry and page
during the CQ/SRQ creation time. Freeing the page is handled when the
mmap free is called. Introduce struct bnxt_re_toggle_mem to carry
the mmap_offset for the lifetime of the GET_TOGGLE_MEM uobject handle.

Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
---
 drivers/infiniband/hw/bnxt_re/ib_verbs.c | 40 +++++++++++++++++++++---
 drivers/infiniband/hw/bnxt_re/ib_verbs.h |  2 ++
 drivers/infiniband/hw/bnxt_re/uapi.c     | 33 +++++++++++--------
 3 files changed, 57 insertions(+), 18 deletions(-)

diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index 1a020c6f5703..9ee2cd0fcda8 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -2161,7 +2161,7 @@ int bnxt_re_destroy_srq(struct ib_srq *ib_srq, struct ib_udata *udata)
 			xa_lock(&uctx->srq_xa);
 			__xa_erase(&uctx->srq_xa, srq->qplib_srq.id);
 			xa_unlock(&uctx->srq_xa);
-			free_page((unsigned long)srq->uctx_srq_page);
+			rdma_user_mmap_entry_remove(&srq->toggle_entry->rdma_entry);
 		}
 	}
 	ib_umem_release(srq->umem);
@@ -2275,10 +2275,17 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq,
 				rc = -ENOMEM;
 				goto fail_destroy_srq;
 			}
+			srq->toggle_entry = bnxt_re_mmap_entry_insert(uctx, (u64)srq->uctx_srq_page,
+								      BNXT_RE_MMAP_TOGGLE_PAGE,
+								      NULL);
+			if (!srq->toggle_entry) {
+				rc = -ENOMEM;
+				goto fail_free_srq_page;
+			}
 			if (xa_is_err(xa_store(&uctx->srq_xa, srq->qplib_srq.id,
 					       ib_srq->uobject, GFP_KERNEL))) {
 				rc = -ENOMEM;
-				goto fail_free_srq_page;
+				goto fail_remove_toggle_entry;
 			}
 			resp.comp_mask |= BNXT_RE_SRQ_TOGGLE_PAGE_SUPPORT;
 		}
@@ -2298,10 +2305,13 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq,
 		xa_lock(&uctx->srq_xa);
 		__xa_erase(&uctx->srq_xa, srq->qplib_srq.id);
 		xa_unlock(&uctx->srq_xa);
-		free_page((unsigned long)srq->uctx_srq_page);
+		goto fail_remove_toggle_entry;
 	}
 	bnxt_qplib_destroy_srq(&rdev->qplib_res, &srq->qplib_srq);
 	goto fail;
+fail_remove_toggle_entry:
+	rdma_user_mmap_entry_remove(&srq->toggle_entry->rdma_entry);
+	goto fail_destroy_srq;
 fail_free_srq_page:
 	free_page((unsigned long)srq->uctx_srq_page);
 fail_destroy_srq:
@@ -3505,7 +3515,7 @@ int bnxt_re_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
 			xa_lock(&uctx->cq_xa);
 			__xa_erase(&uctx->cq_xa, cq->qplib_cq.id);
 			xa_unlock(&uctx->cq_xa);
-			free_page((unsigned long)cq->uctx_cq_page);
+			rdma_user_mmap_entry_remove(&cq->toggle_entry->rdma_entry);
 		}
 	}
 
@@ -3587,10 +3597,16 @@ int bnxt_re_create_user_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *att
 			rc = -ENOMEM;
 			goto destroy_cq;
 		}
+		cq->toggle_entry = bnxt_re_mmap_entry_insert(uctx, (u64)cq->uctx_cq_page,
+							     BNXT_RE_MMAP_TOGGLE_PAGE, NULL);
+		if (!cq->toggle_entry) {
+			rc = -ENOMEM;
+			goto free_cq_page;
+		}
 		if (xa_is_err(xa_store(&uctx->cq_xa, cq->qplib_cq.id,
 				       ibcq->uobject, GFP_KERNEL))) {
 			rc = -ENOMEM;
-			goto free_cq_page;
+			goto remove_toggle_entry;
 		}
 		resp.comp_mask |= BNXT_RE_CQ_TOGGLE_PAGE_SUPPORT;
 	}
@@ -3609,6 +3625,10 @@ int bnxt_re_create_user_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *att
 		__xa_erase(&uctx->cq_xa, cq->qplib_cq.id);
 		xa_unlock(&uctx->cq_xa);
 	}
+remove_toggle_entry:
+	if (cctx->modes.toggle_bits & BNXT_QPLIB_CQ_TOGGLE_BIT)
+		rdma_user_mmap_entry_remove(&cq->toggle_entry->rdma_entry);
+	goto destroy_cq;
 free_cq_page:
 	free_page((unsigned long)cq->uctx_cq_page);
 destroy_cq:
@@ -5053,6 +5073,16 @@ void bnxt_re_mmap_free(struct rdma_user_mmap_entry *rdma_entry)
 	bnxt_entry = container_of(rdma_entry, struct bnxt_re_user_mmap_entry,
 				  rdma_entry);
 
+	/*
+	 * For toggle pages the kernel VA was stored directly in mem_offset
+	 * at creation time (bnxt_re_create_user_cq / bnxt_re_create_srq).
+	 * Free it here — this is the only place it is freed, ensuring the
+	 * page outlives every concurrent bnxt_re_mmap() call that may have
+	 * incremented the entry's reference count.
+	 */
+	if (bnxt_entry->mmap_flag == BNXT_RE_MMAP_TOGGLE_PAGE)
+		free_page((unsigned long)bnxt_entry->mem_offset);
+
 	if (bnxt_entry->dpi_valid)
 		bnxt_qplib_free_uc_dpi(&bnxt_entry->uctx->rdev->qplib_res,
 				       &bnxt_entry->dpi);
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.h b/drivers/infiniband/hw/bnxt_re/ib_verbs.h
index 4c78c183784b..b7b33f6acf91 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.h
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.h
@@ -80,6 +80,7 @@ struct bnxt_re_srq {
 	struct ib_umem		*umem;
 	spinlock_t		lock;		/* protect srq */
 	void			*uctx_srq_page;
+	struct bnxt_re_user_mmap_entry *toggle_entry;
 };
 
 struct bnxt_re_qp {
@@ -114,6 +115,7 @@ struct bnxt_re_cq {
 	struct ib_umem		*resize_umem;
 	int			resize_cqe;
 	void			*uctx_cq_page;
+	struct bnxt_re_user_mmap_entry *toggle_entry;
 };
 
 struct bnxt_re_mr {
diff --git a/drivers/infiniband/hw/bnxt_re/uapi.c b/drivers/infiniband/hw/bnxt_re/uapi.c
index 0ab3512e56f7..c879f5223ea7 100644
--- a/drivers/infiniband/hw/bnxt_re/uapi.c
+++ b/drivers/infiniband/hw/bnxt_re/uapi.c
@@ -213,19 +213,21 @@ DECLARE_UVERBS_GLOBAL_METHODS(BNXT_RE_OBJECT_NOTIFY_DRV,
 			      &UVERBS_METHOD(BNXT_RE_METHOD_NOTIFY_DRV));
 
 /* Toggle MEM */
+struct bnxt_re_toggle_mem {
+	u64 mmap_offset;
+};
+
 static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bundle *attrs)
 {
 	struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs, BNXT_RE_TOGGLE_MEM_HANDLE);
-	enum bnxt_re_mmap_flag mmap_flag = BNXT_RE_MMAP_TOGGLE_PAGE;
 	enum bnxt_re_get_toggle_mem_type res_type;
-	struct bnxt_re_user_mmap_entry *entry;
+	struct bnxt_re_toggle_mem *tmem;
 	struct ib_uobject *res_uobj;
 	struct bnxt_re_ucontext *uctx;
 	struct ib_ucontext *ib_uctx;
 	u32 length = PAGE_SIZE;
-	u64 mem_offset;
+	u64 mmap_offset = 0;
 	u32 offset = 0;
-	u64 addr = 0;
 	u32 res_id;
 	int err;
 
@@ -249,7 +251,9 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bund
 		res_uobj = xa_load(&uctx->cq_xa, res_id);
 		if (res_uobj) {
 			cq = container_of(res_uobj->object, struct bnxt_re_cq, ib_cq);
-			addr = (u64)cq->uctx_cq_page;
+			if (cq->toggle_entry)
+				mmap_offset =
+					rdma_user_mmap_get_offset(&cq->toggle_entry->rdma_entry);
 		}
 		xa_unlock(&uctx->cq_xa);
 	} else if (res_type == BNXT_RE_SRQ_TOGGLE_MEM) {
@@ -259,24 +263,27 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bund
 		res_uobj = xa_load(&uctx->srq_xa, res_id);
 		if (res_uobj) {
 			srq = container_of(res_uobj->object, struct bnxt_re_srq, ib_srq);
-			addr = (u64)srq->uctx_srq_page;
+			if (srq->toggle_entry)
+				mmap_offset =
+					rdma_user_mmap_get_offset(&srq->toggle_entry->rdma_entry);
 		}
 		xa_unlock(&uctx->srq_xa);
 	} else {
 		return -EOPNOTSUPP;
 	}
 
-	if (!addr)
+	if (!mmap_offset)
 		return -EOPNOTSUPP;
 
-	entry = bnxt_re_mmap_entry_insert(uctx, addr, mmap_flag, &mem_offset);
-	if (!entry)
+	tmem = kzalloc_obj(*tmem);
+	if (!tmem)
 		return -ENOMEM;
 
-	uobj->object = entry;
+	tmem->mmap_offset = mmap_offset;
+	uobj->object = tmem;
 	uverbs_finalize_uobj_create(attrs, BNXT_RE_TOGGLE_MEM_HANDLE);
 	err = uverbs_copy_to(attrs, BNXT_RE_TOGGLE_MEM_MMAP_PAGE,
-			     &mem_offset, sizeof(mem_offset));
+			     &mmap_offset, sizeof(mmap_offset));
 	if (err)
 		return err;
 
@@ -297,9 +304,9 @@ static int get_toggle_mem_obj_cleanup(struct ib_uobject *uobject,
 				      enum rdma_remove_reason why,
 				      struct uverbs_attr_bundle *attrs)
 {
-	struct bnxt_re_user_mmap_entry *entry = uobject->object;
+	struct bnxt_re_toggle_mem *tmem = uobject->object;
 
-	rdma_user_mmap_entry_remove(&entry->rdma_entry);
+	kfree(tmem);
 	return 0;
 }
 
-- 
2.39.3


  parent reply	other threads:[~2026-07-13  8:36 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-13 13:58 [PATCH for-next v3 0/4] RDMA/bnxt_re: Update the toggle page handling of CQ and SRQ Selvin Xavier
2026-07-13 13:58 ` [PATCH for-next v3 1/4] RDMA/bnxt_re: Replace per-device hash tables with per-context XArrays Selvin Xavier
2026-07-13 13:58 ` Selvin Xavier [this message]
2026-07-13 13:58 ` [PATCH for-next v3 3/4] RDMA/bnxt_re: Fix toggle page UAF in GET_TOGGLE_MEM with mmap entry refcount Selvin Xavier
2026-07-13 13:58 ` [PATCH for-next v3 4/4] RDMA/bnxt_re: Add uverbs object handle path for CQ/SRQ toggle page Selvin Xavier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260713135830.1934471-3-selvin.xavier@broadcom.com \
    --to=selvin.xavier@broadcom.com \
    --cc=alhouseenyousef@gmail.com \
    --cc=andrew.gospodarek@broadcom.com \
    --cc=jgg@ziepe.ca \
    --cc=kalesh-anakkur.purayil@broadcom.com \
    --cc=leon@kernel.org \
    --cc=linux-rdma@vger.kernel.org \
    --cc=sriharsha.basavapatna@broadcom.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox