mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 13:14:02 +02:00
RDMA/erdma: Hold QP references for AE and CM processing
AE QP fatal events and iWARP CM paths load QPs from dev->qp_xa
and then use or reference them outside the xarray lock.
erdma_destroy_qp() can drop the destroy-path reference and free QP
resources while such a lookup is in flight.
Add erdma_qp_get_by_qpn() to acquire a kref under the xarray
lock with kref_get_unless_zero(). Remove the QP from the xarray
before dropping the destroy-path reference so no new lookup can acquire
it while destruction waits for existing users.
Fixes: 1550557717 ("RDMA/erdma: Add verbs implementation")
Signed-off-by: Cheng Xu <chengyou@linux.alibaba.com>
Link: https://patch.msgid.link/20260730124357.12976-2-chengyou@linux.alibaba.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
This commit is contained in:
parent
98df2aee14
commit
a52eeff320
|
|
@ -1021,10 +1021,9 @@ int erdma_connect(struct iw_cm_id *id, struct iw_cm_conn_param *params)
|
|||
if (laddr->sa_family != AF_INET || raddr->sa_family != AF_INET)
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
qp = find_qp_by_qpn(dev, params->qpn);
|
||||
qp = erdma_qp_get_by_qpn(dev, params->qpn);
|
||||
if (!qp)
|
||||
return -ENOENT;
|
||||
erdma_qp_get(qp);
|
||||
|
||||
ret = sock_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, &s);
|
||||
if (ret < 0)
|
||||
|
|
@ -1154,10 +1153,9 @@ int erdma_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
|
|||
return -ECONNRESET;
|
||||
}
|
||||
|
||||
qp = find_qp_by_qpn(dev, params->qpn);
|
||||
qp = erdma_qp_get_by_qpn(dev, params->qpn);
|
||||
if (!qp)
|
||||
return -ENOENT;
|
||||
erdma_qp_get(qp);
|
||||
|
||||
down_write(&qp->state_lock);
|
||||
if (qp->attrs.iwarp.state > ERDMA_QPS_IWARP_RTR) {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ void erdma_aeq_event_handler(struct erdma_dev *dev)
|
|||
erdma_cq_put(cq);
|
||||
} else {
|
||||
qpn = le32_to_cpu(aeqe->event_data0);
|
||||
qp = find_qp_by_qpn(dev, qpn);
|
||||
qp = erdma_qp_get_by_qpn(dev, qpn);
|
||||
if (!qp)
|
||||
continue;
|
||||
|
||||
|
|
@ -75,6 +75,7 @@ void erdma_aeq_event_handler(struct erdma_dev *dev)
|
|||
if (qp->ibqp.event_handler)
|
||||
qp->ibqp.event_handler(&event,
|
||||
qp->ibqp.qp_context);
|
||||
erdma_qp_put(qp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1369,6 +1369,7 @@ int erdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
|
|||
udata, struct erdma_ucontext, ibucontext);
|
||||
struct erdma_cmdq_destroy_qp_req req;
|
||||
union erdma_mod_qp_params params;
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
down_write(&qp->state_lock);
|
||||
|
|
@ -1396,6 +1397,10 @@ int erdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
|
|||
"failed to destroy QP %u: %d\n",
|
||||
QP_ID(qp), err);
|
||||
|
||||
xa_lock_irqsave(&dev->qp_xa, flags);
|
||||
__xa_erase(&dev->qp_xa, QP_ID(qp));
|
||||
xa_unlock_irqrestore(&dev->qp_xa, flags);
|
||||
|
||||
erdma_qp_put(qp);
|
||||
wait_for_completion(&qp->safe_free);
|
||||
|
||||
|
|
@ -1409,7 +1414,6 @@ int erdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
|
|||
|
||||
if (qp->cep)
|
||||
erdma_cep_put(qp->cep);
|
||||
xa_erase(&dev->qp_xa, QP_ID(qp));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -360,6 +360,21 @@ static inline struct erdma_qp *find_qp_by_qpn(struct erdma_dev *dev, int id)
|
|||
return (struct erdma_qp *)xa_load(&dev->qp_xa, id);
|
||||
}
|
||||
|
||||
static inline struct erdma_qp *erdma_qp_get_by_qpn(struct erdma_dev *dev,
|
||||
int id)
|
||||
{
|
||||
struct erdma_qp *qp;
|
||||
unsigned long flags;
|
||||
|
||||
xa_lock_irqsave(&dev->qp_xa, flags);
|
||||
qp = xa_load(&dev->qp_xa, id);
|
||||
if (qp && !kref_get_unless_zero(&qp->ref))
|
||||
qp = NULL;
|
||||
xa_unlock_irqrestore(&dev->qp_xa, flags);
|
||||
|
||||
return qp;
|
||||
}
|
||||
|
||||
static inline struct erdma_cq *erdma_cq_get_by_cqn(struct erdma_dev *dev,
|
||||
int id)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user