summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeon Romanovsky <leonro@nvidia.com>2026-07-21 18:00:01 +0300
committerLeon Romanovsky <leon@kernel.org>2026-07-22 05:35:11 -0400
commit97f7c2262c28ebcae64fc957ee978646684a5ed9 (patch)
tree859be8670050dd135c68a3e14040cbe33c59742e
parent63d6c2d10c15ba3a41cee15e3cc50fda95c35984 (diff)
downloadlinux-97f7c2262c28ebcae64fc957ee978646684a5ed9.tar.gz
linux-97f7c2262c28ebcae64fc957ee978646684a5ed9.zip
RDMA/mana_ib: drain QP references after partial table insertion
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") Link: https://patch.msgid.link/20260721-if-mana-table-store-qp-qids-partiall-v1-1-8fb3d2d2b559@nvidia.com Reviewed-by: Konstantin Taranov <kotaranov@microsoft.com> Reviewed-by: Long Li <longli@microsoft.com> Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
-rw-r--r--drivers/infiniband/hw/mana/qp.c10
1 files 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,