mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 22:14:03 +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)
|
if (laddr->sa_family != AF_INET || raddr->sa_family != AF_INET)
|
||||||
return -EAFNOSUPPORT;
|
return -EAFNOSUPPORT;
|
||||||
|
|
||||||
qp = find_qp_by_qpn(dev, params->qpn);
|
qp = erdma_qp_get_by_qpn(dev, params->qpn);
|
||||||
if (!qp)
|
if (!qp)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
erdma_qp_get(qp);
|
|
||||||
|
|
||||||
ret = sock_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, &s);
|
ret = sock_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, &s);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
@ -1154,10 +1153,9 @@ int erdma_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
|
||||||
return -ECONNRESET;
|
return -ECONNRESET;
|
||||||
}
|
}
|
||||||
|
|
||||||
qp = find_qp_by_qpn(dev, params->qpn);
|
qp = erdma_qp_get_by_qpn(dev, params->qpn);
|
||||||
if (!qp)
|
if (!qp)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
erdma_qp_get(qp);
|
|
||||||
|
|
||||||
down_write(&qp->state_lock);
|
down_write(&qp->state_lock);
|
||||||
if (qp->attrs.iwarp.state > ERDMA_QPS_IWARP_RTR) {
|
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);
|
erdma_cq_put(cq);
|
||||||
} else {
|
} else {
|
||||||
qpn = le32_to_cpu(aeqe->event_data0);
|
qpn = le32_to_cpu(aeqe->event_data0);
|
||||||
qp = find_qp_by_qpn(dev, qpn);
|
qp = erdma_qp_get_by_qpn(dev, qpn);
|
||||||
if (!qp)
|
if (!qp)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -75,6 +75,7 @@ void erdma_aeq_event_handler(struct erdma_dev *dev)
|
||||||
if (qp->ibqp.event_handler)
|
if (qp->ibqp.event_handler)
|
||||||
qp->ibqp.event_handler(&event,
|
qp->ibqp.event_handler(&event,
|
||||||
qp->ibqp.qp_context);
|
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);
|
udata, struct erdma_ucontext, ibucontext);
|
||||||
struct erdma_cmdq_destroy_qp_req req;
|
struct erdma_cmdq_destroy_qp_req req;
|
||||||
union erdma_mod_qp_params params;
|
union erdma_mod_qp_params params;
|
||||||
|
unsigned long flags;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
down_write(&qp->state_lock);
|
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",
|
"failed to destroy QP %u: %d\n",
|
||||||
QP_ID(qp), err);
|
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);
|
erdma_qp_put(qp);
|
||||||
wait_for_completion(&qp->safe_free);
|
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)
|
if (qp->cep)
|
||||||
erdma_cep_put(qp->cep);
|
erdma_cep_put(qp->cep);
|
||||||
xa_erase(&dev->qp_xa, QP_ID(qp));
|
|
||||||
|
|
||||||
return 0;
|
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);
|
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,
|
static inline struct erdma_cq *erdma_cq_get_by_cqn(struct erdma_dev *dev,
|
||||||
int id)
|
int id)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user