[PATCH rdma-next] RDMA/mana_ib: drain QP references after partial table insertion
Leon Romanovsky <[email protected]> Tue, 21 Jul 2026 18:00:01 +0300
| Newsgroups | org.kernel.vger.linux-hyperv,org.kernel.vger.linux-kernel,org.kernel.vger.linux-rdma |
|---|---|
| Message-ID | <20260721-if-mana-table-store-qp-qids-partiall-v1-1-8fb3d2d2b559@nvidia.com> |
From: Leon Romanovsky <[email protected]> mana_table_store_ud_qp() publishes a QP at its send-queue id before inserting the receive-queue id, dropping the XArray lock between the two xa_insert_irq() calls. A concurrent completion handler can look up the QP and take a transient reference. When the second insertion fails, the rollback erased only the send-queue entry and returned, leaving both the initial table reference and the transient reference outstanding while RDMA core frees the QP, causing a use-after-free. Drain the reference as normal destruction does: drop the initial reference and wait for qp->free, releasing the QP only after every concurrent lookup returns its reference. Fixes: 8001e9257eca ("RDMA/mana_ib: extend mana QP table") Signed-off-by: Leon Romanovsky <[email protected]> --- Konstantin, I saw this in one of the Sashiko runs, and I believe the AI is correct. The reference can be acquired through the GDMA_EQE_RNIC_QP_FATAL event. Thanks --- drivers/infiniband/hw/mana/qp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c index b5ff07e34eb7..c52f3ec14032 100644 --- a/drivers/infiniband/hw/mana/qp.c +++ b/drivers/infiniband/hw/mana/qp.c @@ -472,6 +472,12 @@ static void mana_table_remove_rc_qp(struct mana_ib_dev *mdev, struct mana_ib_qp xa_erase_irq(&mdev->qp_table_wq, qp->ibqp.qp_num); } +static void mana_table_drain_qp_ref(struct mana_ib_qp *qp) +{ + mana_put_qp_ref(qp); + wait_for_completion(&qp->free); +} + static int mana_table_store_ud_qp(struct mana_ib_dev *mdev, struct mana_ib_qp *qp) { u32 qids = qp->ud_qp.queues[MANA_UD_SEND_QUEUE].id | MANA_SENDQ_MASK; @@ -490,6 +496,7 @@ static int mana_table_store_ud_qp(struct mana_ib_dev *mdev, struct mana_ib_qp *q remove_sq: xa_erase_irq(&mdev->qp_table_wq, qids); + mana_table_drain_qp_ref(qp); return err; } @@ -537,8 +544,7 @@ static void mana_table_remove_qp(struct mana_ib_dev *mdev, qp->ibqp.qp_type); return; } - mana_put_qp_ref(qp); - wait_for_completion(&qp->free); + mana_table_drain_qp_ref(qp); } static int mana_ib_create_rc_qp(struct ib_qp *ibqp, struct ib_pd *ibpd, --- base-commit: 74f49255492a62658f36bf2578d7916f1c6ffad1 change-id: 20260721-if-mana-table-store-qp-qids-partiall-afa14f023261 Best regards, -- Leon Romanovsky <[email protected]>