RDMA/irdma: Add refcounting to user ring MRs

Prevent userspace from deregistering the MRs that back QP/CQ/SRQ rings
by bumping the MR's refcount upon association.

Fixes: b48c24c2d7 ("RDMA/irdma: Implement device supported verb APIs")
Signed-off-by: Jacob Moroni <jmoroni@google.com>
Link: https://patch.msgid.link/20260618201458.875740-5-jmoroni@google.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
This commit is contained in:
Jacob Moroni 2026-06-18 20:14:58 +00:00 committed by Leon Romanovsky
parent 971e99623e
commit f67d8a08f6
2 changed files with 49 additions and 2 deletions

View File

@ -1168,6 +1168,12 @@ void irdma_free_qp_rsrc(struct irdma_qp *iwqp)
iwqp->kqp.dma_mem.va = NULL;
kfree(iwqp->kqp.sq_wrid_mem);
kfree(iwqp->kqp.rq_wrid_mem);
if (iwqp->user_mode && iwqp->iwpbl) {
struct irdma_mr *iwmr = iwqp->iwpbl->iwmr;
refcount_dec(&iwmr->user_ring_refs);
}
}
/**

View File

@ -464,6 +464,9 @@ static struct irdma_pbl *irdma_get_pbl(unsigned long va,
list_for_each_entry (iwpbl, pbl_list, list) {
if (iwpbl->user_base == va) {
struct irdma_mr *iwmr = iwpbl->iwmr;
refcount_inc(&iwmr->user_ring_refs);
list_del(&iwpbl->list);
iwpbl->on_list = false;
return iwpbl;
@ -1881,6 +1884,11 @@ static void irdma_srq_free_rsrc(struct irdma_pci_f *rf, struct irdma_srq *iwsrq)
dma_free_coherent(rf->sc_dev.hw->device, iwsrq->kmem.size,
iwsrq->kmem.va, iwsrq->kmem.pa);
iwsrq->kmem.va = NULL;
} else {
/* Not called in any failure path, so iwpbl is valid. */
struct irdma_mr *iwmr = iwsrq->iwpbl->iwmr;
refcount_dec(&iwmr->user_ring_refs);
}
irdma_free_rsrc(rf, rf->allocated_srqs, srq->srq_uk.srq_id);
@ -1903,6 +1911,21 @@ static void irdma_cq_free_rsrc(struct irdma_pci_f *rf, struct irdma_cq *iwcq)
iwcq->kmem_shadow.size,
iwcq->kmem_shadow.va, iwcq->kmem_shadow.pa);
iwcq->kmem_shadow.va = NULL;
} else {
struct irdma_mr *iwmr;
/* May be called in a failure path before iwpbl is valid. */
if (iwcq->iwpbl) {
iwmr = iwcq->iwpbl->iwmr;
refcount_dec(&iwmr->user_ring_refs);
}
if (iwcq->iwpbl_shadow) {
iwmr = iwcq->iwpbl_shadow->iwmr;
refcount_dec(&iwmr->user_ring_refs);
}
}
irdma_free_rsrc(rf, rf->allocated_cqs, cq->cq_uk.cq_id);
@ -2018,7 +2041,7 @@ static int irdma_resize_cq(struct ib_cq *ibcq, unsigned int entries,
struct irdma_modify_cq_info info = {};
struct irdma_dma_mem kmem_buf;
struct irdma_cq_mr *cqmr_buf;
struct irdma_pbl *iwpbl_buf;
struct irdma_pbl *iwpbl_buf = NULL;
struct irdma_device *iwdev;
struct irdma_pci_f *rf;
struct irdma_cq_buf *cq_buf = NULL;
@ -2129,11 +2152,19 @@ static int irdma_resize_cq(struct ib_cq *ibcq, unsigned int entries,
goto error;
spin_lock_irqsave(&iwcq->lock, flags);
if (udata)
if (udata) {
struct irdma_pbl *old_iwpbl = iwcq->iwpbl;
/* Only update if the resize was successful. Otherwise, HW is
* still pointing to the old PBL.
*/
iwcq->iwpbl = iwpbl_buf;
if (old_iwpbl) {
struct irdma_mr *old_iwmr = old_iwpbl->iwmr;
refcount_dec(&old_iwmr->user_ring_refs);
}
}
if (cq_buf) {
cq_buf->kmem_buf = iwcq->kmem;
cq_buf->hw = dev->hw;
@ -2149,6 +2180,11 @@ static int irdma_resize_cq(struct ib_cq *ibcq, unsigned int entries,
return 0;
error:
if (iwpbl_buf) {
struct irdma_mr *iwmr = iwpbl_buf->iwmr;
refcount_dec(&iwmr->user_ring_refs);
}
if (!udata) {
dma_free_coherent(dev->hw->device, kmem_buf.size, kmem_buf.va,
kmem_buf.pa);
@ -2425,6 +2461,11 @@ static int irdma_create_srq(struct ib_srq *ibsrq,
dma_free_coherent(rf->hw.device, iwsrq->kmem.size,
iwsrq->kmem.va, iwsrq->kmem.pa);
free_rsrc:
if (iwsrq->user_mode && iwsrq->iwpbl) {
struct irdma_mr *iwmr = iwsrq->iwpbl->iwmr;
refcount_dec(&iwmr->user_ring_refs);
}
irdma_free_rsrc(rf, rf->allocated_srqs, iwsrq->srq_num);
return err_code;
}