drivers/infiniband/ulp/rtrs/rtrs-clt.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-)
__rtrs_get_permit() scans permits_map with find_first_zero_bit() and
claims the bit with test_and_set_bit_lock(), restarting from bit 0 on a
lost race. Use find_next_zero_bit() to resume from the last position so
a lost race does not rescan the already-set low bits; on reaching the
end, wrap to the beginning to exhaust the map.
Compile-tested: arm64 defconfig + INFINIBAND_RTRS_CLIENT=m, rtrs-clt.o
Reviewed-by: Jack Wang <jinpu.wang@cloud.ionos.com>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Liu Zhenlong <dragonliu2018@gmail.com>
---
drivers/infiniband/ulp/rtrs/rtrs-clt.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c
index d34d7e5f34d6..a1df90243c41 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c
+++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c
@@ -70,19 +70,24 @@ __rtrs_get_permit(struct rtrs_clt_sess *clt, enum rtrs_clt_con_type con_type)
{
size_t max_depth = clt->queue_depth;
struct rtrs_permit *permit;
- int bit;
+ unsigned long bit = 0;
/*
- * Adapted from null_blk get_tag(). Callers from different cpus may
- * grab the same bit, since find_first_zero_bit is not atomic.
- * But then the test_and_set_bit_lock will fail for all the
- * callers but one, so that they will loop again.
- * This way an explicit spinlock is not required.
+ * Callers from different CPUs may grab the same bit, since the bitmap
+ * scan is not atomic. But then the test_and_set_bit_lock() will fail
+ * for all the callers but one, so that they loop again. This way an
+ * explicit spinlock is not required. find_next_zero_bit() resumes
+ * from the last position so that a lost race does not rescan the
+ * already-set low bits; if it reaches the end, wrap to the beginning
+ * to exhaust the map and still find a permit freed below the cursor.
*/
do {
- bit = find_first_zero_bit(clt->permits_map, max_depth);
- if (bit >= max_depth)
- return NULL;
+ bit = find_next_zero_bit(clt->permits_map, max_depth, bit);
+ if (bit >= max_depth) {
+ bit = find_first_zero_bit(clt->permits_map, max_depth);
+ if (bit >= max_depth)
+ return NULL;
+ }
} while (test_and_set_bit_lock(bit, clt->permits_map));
permit = get_permit(clt, bit);
--
2.55.0
Hi Jack, Thanks for the review. Since I omitted the changelog in v2: the only change from v1 is a simplified commit message; code unchanged, your Reviewed-by carried. Best, Zhenlong
© 2016 - 2026 Red Hat, Inc.