summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeon Romanovsky <leonro@nvidia.com>2026-07-26 15:21:44 +0300
committerLeon Romanovsky <leonro@nvidia.com>2026-07-29 07:46:56 -0400
commitfdfb5cea4bf070cdb31d997efd87bb684df041fd (patch)
tree45ee73df1eb6802e6cd424978b9d29ce032211f5
parent033a79e308e4fe832b0924347eda8c4364055174 (diff)
downloadlinux-next-fdfb5cea4bf070cdb31d997efd87bb684df041fd.tar.gz
linux-next-fdfb5cea4bf070cdb31d997efd87bb684df041fd.zip
RDMA/cxgb4: free STAG index when TPT entry write fails
write_tpt_entry() allocates a new STAG index with c4iw_get_resource() and bumps stats.stag.cur before programming the entry. When write_adapter_mem() fails, it returns the error without releasing the index or reversing the statistic. No MR is inserted into rhp->mrs, so deregistration never reclaims it, leaking the index until device teardown. Record whether this call allocated the index and, on a failed write, return it to tpt_table and decrement stats.stag.cur. Key the rollback on both the write error and that flag, not the error alone: a non-reset update carries a caller-owned STAG that this call did not allocate and must not free. Fixes: ec3eead21718 ("RDMA/cxgb4: Remove kfifo usage") Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
-rw-r--r--drivers/infiniband/hw/cxgb4/mem.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c
index 1413bd0c0752..c28f76a32d90 100644
--- a/drivers/infiniband/hw/cxgb4/mem.c
+++ b/drivers/infiniband/hw/cxgb4/mem.c
@@ -254,6 +254,7 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
int err;
struct fw_ri_tpte *tpt;
u32 stag_idx;
+ bool stag_idx_allocated = false;
static atomic_t key;
if (c4iw_fatal_error(rdev)) {
@@ -281,6 +282,7 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
return -ENOMEM;
}
mutex_lock(&rdev->stats.lock);
+ stag_idx_allocated = true;
rdev->stats.stag.cur += 32;
if (rdev->stats.stag.cur > rdev->stats.stag.max)
rdev->stats.stag.max = rdev->stats.stag.cur;
@@ -315,7 +317,7 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
(rdev->lldi.vr->stag.start >> 5),
sizeof(*tpt), tpt, skb, wr_waitp);
- if (reset_tpt_entry) {
+ if (reset_tpt_entry || (err && stag_idx_allocated)) {
c4iw_put_resource(&rdev->resource.tpt_table, stag_idx);
mutex_lock(&rdev->stats.lock);
rdev->stats.stag.cur -= 32;