All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next v2 2/2] net/smc: reduce TX slot contention with exclusive wait
  2026-05-28  8:48 [PATCH net-next 0/2] net/smc: transition to RDMA core CQ pooling D. Wythe
@ 2026-05-28  8:48 ` D. Wythe
  2026-06-08 14:04   ` Dust Li
  0 siblings, 1 reply; 5+ messages in thread
From: D. Wythe @ 2026-05-28  8:48 UTC (permalink / raw)
  To: David S. Miller, Dust Li, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Sidraya Jayagond, Wenjia Zhang
  Cc: Mahanta Jambigi, Simon Horman, Tony Lu, Wen Gu, linux-kernel,
	linux-rdma, linux-s390, netdev, oliver.yang, pasic

smc_wr_tx_get_free_slot() waits for a free TX slot with
wait_event_interruptible_timeout(). Since the wait_event family
enqueues waiters as non-exclusive, wake_up() may wake multiple
waiters even though only one can use the slot, causing
thundering-herd contention when slots are scarce.

Use an exclusive wait loop with prepare_to_wait_exclusive() so
wake_up() wakes only one waiter per freed slot.
smc_wr_wakeup_tx_wait() still uses wake_up_all() during link
teardown, so teardown behavior is unchanged.

Performance measured with netperf TCP_RR (63 flows, 200B write /
1000B read, 60s duration):

+-------------------------------+---------------+---------------+
| smcr_max_conns_per_lgr        | 32            | 255           |
|-------------------------------+---------------+---------------|
| before                        | 4.85 Gb/s     | 657.95 Mb/s   |
|-------------------------------+---------------+---------------|
| after                         | 5.01 Gb/s     | 2.2 Gb/s      |
+-------------------------------+---------------+---------------+

Signed-off-by: D. Wythe <alibuda@linux.alibaba.com>
---
 net/smc/smc_wr.c | 36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/net/smc/smc_wr.c b/net/smc/smc_wr.c
index 130bc6c26fb3..3cb47f77130e 100644
--- a/net/smc/smc_wr.c
+++ b/net/smc/smc_wr.c
@@ -153,9 +153,11 @@ int smc_wr_tx_get_free_slot(struct smc_link *link,
 			    struct smc_rdma_wr **wr_rdma_buf,
 			    struct smc_wr_tx_pend_priv **wr_pend_priv)
 {
+	unsigned long timeout = SMC_WR_TX_WAIT_FREE_SLOT_TIME;
 	struct smc_link_group *lgr = smc_get_lgr(link);
 	struct smc_wr_tx_pend *wr_pend;
 	u32 idx = link->wr_tx_cnt;
+	DEFINE_WAIT(wait);
 	int rc;
 
 	*wr_buf = NULL;
@@ -165,17 +167,31 @@ int smc_wr_tx_get_free_slot(struct smc_link *link,
 		if (rc)
 			return rc;
 	} else {
-		rc = wait_event_interruptible_timeout(
-			link->wr_tx_wait,
-			!smc_link_sendable(link) ||
-			lgr->terminating ||
-			(smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY),
-			SMC_WR_TX_WAIT_FREE_SLOT_TIME);
-		if (!rc) {
-			/* timeout - terminate link */
-			smcr_link_down_cond_sched(link);
-			return -EPIPE;
+		rc = 0;
+		for (;;) {
+			prepare_to_wait_exclusive(&link->wr_tx_wait, &wait,
+						  TASK_INTERRUPTIBLE);
+			if (!smc_link_sendable(link) || lgr->terminating ||
+			    smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY)
+				break;
+			timeout = schedule_timeout(timeout);
+			/* re-check */
+			if (!smc_link_sendable(link) || lgr->terminating ||
+			    smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY)
+				break;
+			if (!timeout) {
+				/* timeout - terminate link */
+				smcr_link_down_cond_sched(link);
+				break;
+			}
+			if (signal_pending(current)) {
+				rc = -ERESTARTSYS;
+				break;
+			}
 		}
+		finish_wait(&link->wr_tx_wait, &wait);
+		if (rc)
+			return rc;
 		if (idx == link->wr_tx_cnt)
 			return -EPIPE;
 	}
-- 
2.45.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH net-next v2 2/2] net/smc: reduce TX slot contention with exclusive wait
  2026-05-28  8:48 ` [PATCH net-next v2 2/2] net/smc: reduce TX slot contention with exclusive wait D. Wythe
@ 2026-06-08 14:04   ` Dust Li
  0 siblings, 0 replies; 5+ messages in thread
From: Dust Li @ 2026-06-08 14:04 UTC (permalink / raw)
  To: D. Wythe, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Sidraya Jayagond, Wenjia Zhang
  Cc: Mahanta Jambigi, Simon Horman, Tony Lu, Wen Gu, linux-kernel,
	linux-rdma, linux-s390, netdev, oliver.yang, pasic

On 2026-05-28 16:48:19, D. Wythe wrote:
>smc_wr_tx_get_free_slot() waits for a free TX slot with
>wait_event_interruptible_timeout(). Since the wait_event family
>enqueues waiters as non-exclusive, wake_up() may wake multiple
>waiters even though only one can use the slot, causing
>thundering-herd contention when slots are scarce.
>
>Use an exclusive wait loop with prepare_to_wait_exclusive() so
>wake_up() wakes only one waiter per freed slot.
>smc_wr_wakeup_tx_wait() still uses wake_up_all() during link
>teardown, so teardown behavior is unchanged.
>
>Performance measured with netperf TCP_RR (63 flows, 200B write /
>1000B read, 60s duration):
>
>+-------------------------------+---------------+---------------+
>| smcr_max_conns_per_lgr        | 32            | 255           |
>|-------------------------------+---------------+---------------|
>| before                        | 4.85 Gb/s     | 657.95 Mb/s   |
>|-------------------------------+---------------+---------------|
>| after                         | 5.01 Gb/s     | 2.2 Gb/s      |
>+-------------------------------+---------------+---------------+
>
>Signed-off-by: D. Wythe <alibuda@linux.alibaba.com>
>---
> net/smc/smc_wr.c | 36 ++++++++++++++++++++++++++----------
> 1 file changed, 26 insertions(+), 10 deletions(-)
>
>diff --git a/net/smc/smc_wr.c b/net/smc/smc_wr.c
>index 130bc6c26fb3..3cb47f77130e 100644
>--- a/net/smc/smc_wr.c
>+++ b/net/smc/smc_wr.c
>@@ -153,9 +153,11 @@ int smc_wr_tx_get_free_slot(struct smc_link *link,
> 			    struct smc_rdma_wr **wr_rdma_buf,
> 			    struct smc_wr_tx_pend_priv **wr_pend_priv)
> {
>+	unsigned long timeout = SMC_WR_TX_WAIT_FREE_SLOT_TIME;
> 	struct smc_link_group *lgr = smc_get_lgr(link);
> 	struct smc_wr_tx_pend *wr_pend;
> 	u32 idx = link->wr_tx_cnt;
>+	DEFINE_WAIT(wait);
> 	int rc;
> 
> 	*wr_buf = NULL;
>@@ -165,17 +167,31 @@ int smc_wr_tx_get_free_slot(struct smc_link *link,
> 		if (rc)
> 			return rc;
> 	} else {
>-		rc = wait_event_interruptible_timeout(
>-			link->wr_tx_wait,
>-			!smc_link_sendable(link) ||
>-			lgr->terminating ||
>-			(smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY),
>-			SMC_WR_TX_WAIT_FREE_SLOT_TIME);
>-		if (!rc) {
>-			/* timeout - terminate link */
>-			smcr_link_down_cond_sched(link);
>-			return -EPIPE;
>+		rc = 0;
>+		for (;;) {
>+			prepare_to_wait_exclusive(&link->wr_tx_wait, &wait,
>+						  TASK_INTERRUPTIBLE);
>+			if (!smc_link_sendable(link) || lgr->terminating ||
>+			    smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY)
>+				break;
>+			timeout = schedule_timeout(timeout);
>+			/* re-check */
>+			if (!smc_link_sendable(link) || lgr->terminating ||
>+			    smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY)
>+				break;
>+			if (!timeout) {
>+				/* timeout - terminate link */
>+				smcr_link_down_cond_sched(link);
>+				break;
>+			}

The change itself looks correct to me. But I think we should probably define
a wait_event_interruptible_exclusive_timeout() helper in include/linux/wait.h
rather than open-coding it in smc ?

>+			if (signal_pending(current)) {
>+				rc = -ERESTARTSYS;
>+				break;
>+			}
> 		}

One more thing, seems we changed the signal here, it's better to add a comment
or note it in the commit message.

Best regards,
Dust


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH net-next v2 0/2] net/smc: fix v2 slot clearing and reduce TX slot contention
@ 2026-08-21  9:17 D. Wythe
  2026-08-21  9:17 ` [PATCH net-next v2 1/2] net/smc: clear the correct v2 slot and buffer in smc_wr_tx_put_slot() D. Wythe
  2026-08-21  9:17 ` [PATCH net-next v2 2/2] net/smc: reduce TX slot contention with exclusive wait D. Wythe
  0 siblings, 2 replies; 5+ messages in thread
From: D. Wythe @ 2026-08-21  9:17 UTC (permalink / raw)
  To: mjambigi, wenjia, wintera, dust.li, tonylu, guwen
  Cc: kuba, davem, netdev, linux-s390, linux-rdma, leonro, pabeni,
	edumazet, sidraya, jaka, oliver.yang

This series contains the two reviewed patches from the previously posted
"net/smc: transition to RDMA core CQ pooling" series (v4), reposted as a
standalone series so they can land independently. The remaining CQ pooling
patch will be reposted separately after these two are merged.

Patch 1 fixes smc_wr_tx_put_slot() to clear the v2 pending slot and buffer
structures instead of the pointer variables, the memset targets were the
8-byte pointers themselves so the structures were never actually cleared.
Patch 2 reduces TX slot contention by switching TX slot allocation from
non-exclusive wait_event() to prepare_to_wait_exclusive(), avoiding
thundering-herd wakes when slots are scarce.

For patch 2, uperf numbers are now included in the commit message, as
requested by Mahanta during v1 review. The short version is that the
gain tracks how often the TX slot wait path is actually taken: with the
default sysctl settings, where a link group multiplexes many connections
over a small send queue, throughput improves by 134% on the 200x1000
request/response workload and by 458% on the 1-byte ping-pong workload;
with a tuned configuration where slots are rarely exhausted, the change
is neutral (+3.4% and +1.0%, i.e. within noise). See patch 2 for the
full table.

Link: https://lore.kernel.org/netdev/20260721175309.321b6503@kernel.org/
Link: https://lore.kernel.org/netdev/20260716113745.65234-1-alibuda@linux.alibaba.com/

---
v1 -> v2:
 - patch 2: add uperf baseline vs patched throughput figures to the
   commit message, as requested by Mahanta Jambigi. No functional
   change.
   Link: https://lore.kernel.org/netdev/e16d16f1-029b-4d30-b393-2e9e525a2998@linux.ibm.com/
 - patch 1: unchanged.

v1: https://lore.kernel.org/netdev/20260806064252.39180-1-alibuda@linux.alibaba.com/

D. Wythe (2):
  net/smc: clear the correct v2 slot and buffer in smc_wr_tx_put_slot()
  net/smc: reduce TX slot contention with exclusive wait

 net/smc/smc_wr.c | 44 ++++++++++++++++++++++++++++++--------------
 1 file changed, 30 insertions(+), 14 deletions(-)

-- 
2.45.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH net-next v2 1/2] net/smc: clear the correct v2 slot and buffer in smc_wr_tx_put_slot()
  2026-08-21  9:17 [PATCH net-next v2 0/2] net/smc: fix v2 slot clearing and reduce TX slot contention D. Wythe
@ 2026-08-21  9:17 ` D. Wythe
  2026-08-21  9:17 ` [PATCH net-next v2 2/2] net/smc: reduce TX slot contention with exclusive wait D. Wythe
  1 sibling, 0 replies; 5+ messages in thread
From: D. Wythe @ 2026-08-21  9:17 UTC (permalink / raw)
  To: mjambigi, wenjia, wintera, dust.li, tonylu, guwen
  Cc: kuba, davem, netdev, linux-s390, linux-rdma, leonro, pabeni,
	edumazet, sidraya, jaka, oliver.yang

smc_wr_tx_put_slot() tries to reset the v2 pending slot and buffer with
memset(&link->wr_tx_v2_pend, 0, sizeof(link->wr_tx_v2_pend)) and the
equivalent for wr_tx_buf_v2. Both are pointers, so this zeroes the 8-byte
pointer variable instead of the structure it points to. The pending slot
and buffer are therefore never actually cleared, and the pointers get
overwritten with NULL.

Pass the pointers directly and use sizeof(*pointer) so the intended
structures are cleared.

Fixes: 8799e310fb3f ("net/smc: add v2 support to the work request layer")
Signed-off-by: D. Wythe <alibuda@linux.alibaba.com>
Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
Reviewed-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
---
 net/smc/smc_wr.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/net/smc/smc_wr.c b/net/smc/smc_wr.c
index 59c92b46945c..6b5add922993 100644
--- a/net/smc/smc_wr.c
+++ b/net/smc/smc_wr.c
@@ -288,10 +288,10 @@ int smc_wr_tx_put_slot(struct smc_link *link,
 	} else if (link->lgr->smc_version == SMC_V2 &&
 		   pend->idx == link->wr_tx_cnt) {
 		/* Large v2 buffer */
-		memset(&link->wr_tx_v2_pend, 0,
-		       sizeof(link->wr_tx_v2_pend));
-		memset(&link->lgr->wr_tx_buf_v2, 0,
-		       sizeof(link->lgr->wr_tx_buf_v2));
+		memset(link->wr_tx_v2_pend, 0,
+		       sizeof(*link->wr_tx_v2_pend));
+		memset(link->lgr->wr_tx_buf_v2, 0,
+		       sizeof(*link->lgr->wr_tx_buf_v2));
 		return 1;
 	}
 
-- 
2.45.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH net-next v2 2/2] net/smc: reduce TX slot contention with exclusive wait
  2026-08-21  9:17 [PATCH net-next v2 0/2] net/smc: fix v2 slot clearing and reduce TX slot contention D. Wythe
  2026-08-21  9:17 ` [PATCH net-next v2 1/2] net/smc: clear the correct v2 slot and buffer in smc_wr_tx_put_slot() D. Wythe
@ 2026-08-21  9:17 ` D. Wythe
  1 sibling, 0 replies; 5+ messages in thread
From: D. Wythe @ 2026-08-21  9:17 UTC (permalink / raw)
  To: mjambigi, wenjia, wintera, dust.li, tonylu, guwen
  Cc: kuba, davem, netdev, linux-s390, linux-rdma, leonro, pabeni,
	edumazet, sidraya, jaka, oliver.yang

smc_wr_tx_get_free_slot() waits for a free TX slot with
wait_event_interruptible_timeout(). Since the wait_event family
enqueues waiters as non-exclusive, wake_up() may wake multiple
waiters even though only one can use the slot, causing
thundering-herd contention when slots are scarce.

Use an exclusive wait loop with prepare_to_wait_exclusive() so
wake_up() wakes only one waiter per freed slot.
smc_wr_wakeup_tx_wait() still uses wake_up_all() during link
teardown, so teardown behavior is unchanged.

This also corrects the return value on a pending signal: the previous
wait_event_interruptible_timeout() path fell through to the "no free
slot" case and returned -EPIPE, masking the signal as a connection
error. The open-coded loop now returns -ERESTARTSYS, matching the
standard interruptible-wait semantics and letting the syscall restart
machinery handle it.

Performance
===========

Measured with uperf between two peers over SMC-R. The benefit depends
on how often the TX slot wait path is actually taken.

With the default settings, where many connections share a link group
and the send queue is small, slots are scarce and the wait path is hot:

  net.smc.smcr_max_conns_per_lgr = 255
  net.smc.smcr_max_send_wr       = 16
  net.smc.smcr_max_recv_wr       = 48

  workload                 baseline      patched     delta
  ---------------------------------------------------------
  rr1c-200x1000-50.xml     655.06 Mb/s   1.53 Gb/s   +134%
  rr1c-1x1-250.xml         371.03 Kb/s   2.07 Mb/s   +458%

With a tuned configuration, where slots are mostly available and the
wait path is rarely entered, the change is neutral to slightly positive:

  net.smc.smcr_max_conns_per_lgr = 32
  net.smc.smcr_max_send_wr       = 64
  net.smc.smcr_max_recv_wr       = 64

  workload                 baseline      patched     delta
  ---------------------------------------------------------
  rr1c-200x1000-50.xml     1.74 Gb/s     1.80 Gb/s   +3.4%
  rr1c-1x1-250.xml         3.11 Mb/s     3.14 Mb/s   +1.0%

So the change does not regress the uncontended case, and recovers most
of the throughput lost to thundering-herd wakeups once slots become
scarce.

Signed-off-by: D. Wythe <alibuda@linux.alibaba.com>
Reviewed-by: Wen Gu <guwen@linux.alibaba.com>
---
 net/smc/smc_wr.c | 36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/net/smc/smc_wr.c b/net/smc/smc_wr.c
index 6b5add922993..2cdd4063c13d 100644
--- a/net/smc/smc_wr.c
+++ b/net/smc/smc_wr.c
@@ -198,11 +198,13 @@ int smc_wr_tx_get_free_slot(struct smc_link *link,
 			    struct smc_rdma_wr **wr_rdma_buf,
 			    struct smc_wr_tx_pend_priv **wr_pend_priv)
 {
+	unsigned long timeout = SMC_WR_TX_WAIT_FREE_SLOT_TIME;
 	struct smc_link_group *lgr = smc_get_lgr(link);
 	struct smc_wr_tx_pend *wr_pend;
 	u32 idx = link->wr_tx_cnt;
 	struct ib_send_wr *wr_ib;
 	u64 wr_id;
+	DEFINE_WAIT(wait);
 	int rc;
 
 	*wr_buf = NULL;
@@ -212,17 +214,31 @@ int smc_wr_tx_get_free_slot(struct smc_link *link,
 		if (rc)
 			return rc;
 	} else {
-		rc = wait_event_interruptible_timeout(
-			link->wr_tx_wait,
-			!smc_link_sendable(link) ||
-			lgr->terminating ||
-			(smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY),
-			SMC_WR_TX_WAIT_FREE_SLOT_TIME);
-		if (!rc) {
-			/* timeout - terminate link */
-			smcr_link_down_cond_sched(link);
-			return -EPIPE;
+		rc = 0;
+		for (;;) {
+			prepare_to_wait_exclusive(&link->wr_tx_wait, &wait,
+						  TASK_INTERRUPTIBLE);
+			if (!smc_link_sendable(link) || lgr->terminating ||
+			    smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY)
+				break;
+			timeout = schedule_timeout(timeout);
+			/* re-check */
+			if (!smc_link_sendable(link) || lgr->terminating ||
+			    smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY)
+				break;
+			if (!timeout) {
+				/* timeout - terminate link */
+				smcr_link_down_cond_sched(link);
+				break;
+			}
+			if (signal_pending(current)) {
+				rc = -ERESTARTSYS;
+				break;
+			}
 		}
+		finish_wait(&link->wr_tx_wait, &wait);
+		if (rc)
+			return rc;
 		if (idx == link->wr_tx_cnt)
 			return -EPIPE;
 	}
-- 
2.45.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-08-21  9:17 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-21  9:17 [PATCH net-next v2 0/2] net/smc: fix v2 slot clearing and reduce TX slot contention D. Wythe
2026-08-21  9:17 ` [PATCH net-next v2 1/2] net/smc: clear the correct v2 slot and buffer in smc_wr_tx_put_slot() D. Wythe
2026-08-21  9:17 ` [PATCH net-next v2 2/2] net/smc: reduce TX slot contention with exclusive wait D. Wythe
  -- strict thread matches above, loose matches on Subject: below --
2026-05-28  8:48 [PATCH net-next 0/2] net/smc: transition to RDMA core CQ pooling D. Wythe
2026-05-28  8:48 ` [PATCH net-next v2 2/2] net/smc: reduce TX slot contention with exclusive wait D. Wythe
2026-06-08 14:04   ` Dust Li

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.