]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
RDMA/hns: Fix xarray race in hns_roce_create_srq()
authorJason Gunthorpe <jgg@nvidia.com>
Tue, 28 Apr 2026 16:17:46 +0000 (13:17 -0300)
committerJason Gunthorpe <jgg@nvidia.com>
Sat, 2 May 2026 18:30:48 +0000 (15:30 -0300)
Sashiko points out that once the srq memory is stored into the xarray by
alloc_srqc() it can immediately be looked up by:

xa_lock(&srq_table->xa);
srq = xa_load(&srq_table->xa, srqn & (hr_dev->caps.num_srqs - 1));
if (srq)
refcount_inc(&srq->refcount);
xa_unlock(&srq_table->xa);

Which will fail refcount debug because the refcount is 0 and then crash:

srq->event(srq, event_type);

Because event is NULL.

Use refcount_inc_not_zero() instead to ensure a partially prepared srq is
never retrieved from the event handler and fix the ordering of the
initialization so refcount becomes 1 only after it is fully ready.

All the initialization must be done before calling free_srqc() since it
depends on the completion and refcount.

Fixes: 9a4435375cd1 ("IB/hns: Add driver files for hns RoCE driver")
Link: https://sashiko.dev/#/patchset/0-v1-e911b76a94d1%2B65d95-rdma_udata_rep_jgg%40nvidia.com?part=3
Link: https://patch.msgid.link/r/13-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com
Reviewed-by: Junxian Huang <huangjunxian6@hisilicon.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
drivers/infiniband/hw/hns/hns_roce_srq.c

index cb848e8e6bbd76a3d30c1c7234abbcd6147edaf7..8b94cbdfa54dfa83f6f2bdf0f28d06d3dbc1430d 100644 (file)
@@ -16,8 +16,8 @@ void hns_roce_srq_event(struct hns_roce_dev *hr_dev, u32 srqn, int event_type)
 
        xa_lock(&srq_table->xa);
        srq = xa_load(&srq_table->xa, srqn & (hr_dev->caps.num_srqs - 1));
-       if (srq)
-               refcount_inc(&srq->refcount);
+       if (srq && !refcount_inc_not_zero(&srq->refcount))
+               srq = NULL;
        xa_unlock(&srq_table->xa);
 
        if (!srq) {
@@ -470,6 +470,10 @@ int hns_roce_create_srq(struct ib_srq *ib_srq,
        if (ret)
                goto err_srqn;
 
+       srq->event = hns_roce_ib_srq_event;
+       init_completion(&srq->free);
+       refcount_set_release(&srq->refcount, 1);
+
        if (udata) {
                resp.cap_flags = srq->cap_flags;
                resp.srqn = srq->srqn;
@@ -480,10 +484,6 @@ int hns_roce_create_srq(struct ib_srq *ib_srq,
                }
        }
 
-       srq->event = hns_roce_ib_srq_event;
-       refcount_set(&srq->refcount, 1);
-       init_completion(&srq->free);
-
        return 0;
 
 err_srqc: