* [PATCH net-next v1 0/2] net/smc: fix v2 slot clearing and reduce TX slot contention
@ 2026-08-06 6:42 D. Wythe
2026-08-06 6:42 ` [PATCH net-next v1 1/2] net/smc: clear the correct v2 slot and buffer in smc_wr_tx_put_slot() D. Wythe
2026-08-06 6:42 ` [PATCH net-next v1 2/2] net/smc: reduce TX slot contention with exclusive wait D. Wythe
0 siblings, 2 replies; 6+ messages in thread
From: D. Wythe @ 2026-08-06 6:42 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.
Link: https://lore.kernel.org/netdev/20260721175309.321b6503@kernel.org/
Link: https://lore.kernel.org/netdev/20260716113745.65234-1-alibuda@linux.alibaba.com/
---
This is a repost of patch 1/2 and 2/2 from the v4 "net/smc: transition to
RDMA core CQ pooling" series, with no code changes. Version numbering is
restarted at v1 since the series is now standalone.
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] 6+ messages in thread
* [PATCH net-next v1 1/2] net/smc: clear the correct v2 slot and buffer in smc_wr_tx_put_slot()
2026-08-06 6:42 [PATCH net-next v1 0/2] net/smc: fix v2 slot clearing and reduce TX slot contention D. Wythe
@ 2026-08-06 6:42 ` D. Wythe
2026-08-07 6:43 ` sashiko-bot
2026-08-06 6:42 ` [PATCH net-next v1 2/2] net/smc: reduce TX slot contention with exclusive wait D. Wythe
1 sibling, 1 reply; 6+ messages in thread
From: D. Wythe @ 2026-08-06 6:42 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] 6+ messages in thread
* [PATCH net-next v1 2/2] net/smc: reduce TX slot contention with exclusive wait
2026-08-06 6:42 [PATCH net-next v1 0/2] net/smc: fix v2 slot clearing and reduce TX slot contention D. Wythe
2026-08-06 6:42 ` [PATCH net-next v1 1/2] net/smc: clear the correct v2 slot and buffer in smc_wr_tx_put_slot() D. Wythe
@ 2026-08-06 6:42 ` D. Wythe
2026-08-07 5:45 ` Mahanta Jambigi
2026-08-07 6:43 ` sashiko-bot
1 sibling, 2 replies; 6+ messages in thread
From: D. Wythe @ 2026-08-06 6:42 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.
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] 6+ messages in thread
* Re: [PATCH net-next v1 2/2] net/smc: reduce TX slot contention with exclusive wait
2026-08-06 6:42 ` [PATCH net-next v1 2/2] net/smc: reduce TX slot contention with exclusive wait D. Wythe
@ 2026-08-07 5:45 ` Mahanta Jambigi
2026-08-07 6:43 ` sashiko-bot
1 sibling, 0 replies; 6+ messages in thread
From: Mahanta Jambigi @ 2026-08-07 5:45 UTC (permalink / raw)
To: D. Wythe, wenjia, wintera, dust.li, tonylu, guwen
Cc: kuba, davem, netdev, linux-s390, linux-rdma, leonro, pabeni,
edumazet, sidraya, jaka, oliver.yang
On 06/08/26 12:12 pm, 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.
Have you run any performance benchmarks (e.g. redis-benchmark or uperf)
to quantify the benefit of this change?
Since the motivation is to reduce contention caused by multiple waiters
being awakened for a single available TX slot, it would be helpful to
see measurable results. Please share the baseline and patched throughput
figures, and any observed throughput differences.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next v1 2/2] net/smc: reduce TX slot contention with exclusive wait
2026-08-06 6:42 ` [PATCH net-next v1 2/2] net/smc: reduce TX slot contention with exclusive wait D. Wythe
2026-08-07 5:45 ` Mahanta Jambigi
@ 2026-08-07 6:43 ` sashiko-bot
1 sibling, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-08-07 6:43 UTC (permalink / raw)
To: D. Wythe; +Cc: Alexander Gordeev, Heiko Carstens, linux-s390, Vasily Gorbik
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] The open-coded exclusive wait loop introduces a lost wakeup vulnerability by failing to check the condition before enqueuing.
Pre-existing issues:
- [High] Returning -ERESTARTSYS from smc_wr_tx_get_free_slot causes silent data stalling because the caller does not schedule tx_work to retry, and the error is ignored by sendmsg.
--
--- Patch [2]: [PATCH net-next v1 2/2] net/smc: reduce TX slot contention with exclusive wait ---
commit bcc5b21bf03b53f401940337c34d2ab052835d45
Author: D. Wythe <alibuda@linux.alibaba.com>
net/smc: reduce TX slot contention with exclusive wait
This patch modifies smc_wr_tx_get_free_slot() to use an exclusive wait loop
using prepare_to_wait_exclusive(). It also updates the return value on a
pending signal from -EPIPE to -ERESTARTSYS to match standard wait semantics.
> diff --git a/net/smc/smc_wr.c b/net/smc/smc_wr.c
> index 6b5add9229937..2cdd4063c13d6 100644
> --- a/net/smc/smc_wr.c
> +++ b/net/smc/smc_wr.c
[ ... ]
> @@ -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;
[Severity: High]
Does this open-coded exclusive wait loop introduce a lost wakeup regression?
By calling prepare_to_wait_exclusive() before checking if a slot is available,
the task is unconditionally added to the waitqueue. If it then finds a free
slot immediately and breaks, it remains on the waitqueue until finish_wait() is
called.
If another slot is freed concurrently, an exclusive wake_up() could wake this
exiting task and stop iterating. This absorbs the wakeup and starves other
threads that are actually sleeping on the queue.
This could cause a 10-second stall for the starved thread, leading to a link
termination via smcr_link_down_cond_sched().
> + 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;
> + }
[Severity: High]
This is a pre-existing issue, but does returning -ERESTARTSYS
here cause silent data stalling if the caller does not schedule a retry?
If we look at smcr_tx_sndbuf_nonempty() in net/smc/smc_tx.c, it only schedules
tx_work if the return value is -EBUSY:
if (rc == -EBUSY) {
...
mod_delayed_work(conn->lgr->tx_wq, &conn->tx_work,
SMC_TX_WORK_DELAY);
}
return rc;
And in smc_tx_sendmsg() in net/smc/smc_tx.c, the return value is ignored:
if (!smc_tx_should_cork(smc, msg))
smc_tx_sndbuf_nonempty(conn);
If the syscall is interrupted by a signal, and the data was already copied to
sndbuf, smc_tx_sendmsg() ignores the return value and returns success to
userspace. Since tx_work is not scheduled for -ERESTARTSYS, the data could be
permanently stuck in the buffer.
> }
> + finish_wait(&link->wr_tx_wait, &wait);
> + if (rc)
> + return rc;
> if (idx == link->wr_tx_cnt)
> return -EPIPE;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260806064252.39180-1-alibuda@linux.alibaba.com?part=2
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next v1 1/2] net/smc: clear the correct v2 slot and buffer in smc_wr_tx_put_slot()
2026-08-06 6:42 ` [PATCH net-next v1 1/2] net/smc: clear the correct v2 slot and buffer in smc_wr_tx_put_slot() D. Wythe
@ 2026-08-07 6:43 ` sashiko-bot
0 siblings, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-08-07 6:43 UTC (permalink / raw)
To: D. Wythe; +Cc: Heiko Carstens, linux-s390, Vasily Gorbik, Alexander Gordeev
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Non-atomic clearing of `wr_tx_v2_pend` before `wr_tx_buf_v2` creates a TOCTOU race that prematurely signals slot availability, corrupting concurrent V2 messages and control data.
- [High] An error completion for a V1 work request unconditionally zeroes out the link group-wide V2 buffer, corrupting concurrent V2 messages on other links.
--
--- Patch [1]: [PATCH net-next v1 1/2] net/smc: clear the correct v2 slot and buffer in smc_wr_tx_put_slot() ---
commit 4fe2881d4ba7f681ee22c596087bf040cfe5c6f0
Author: D. Wythe <alibuda@linux.alibaba.com>
net/smc: clear the correct v2 slot and buffer in smc_wr_tx_put_slot()
This patch fixes an issue where 8-byte pointer variables were being zeroed
instead of the structures they point to. It passes the pointers directly
and uses sizeof(*pointer) to properly clear the intended structures.
> diff --git a/net/smc/smc_wr.c b/net/smc/smc_wr.c
> --- 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));
[Severity: High]
This isn't a bug introduced by this patch, but it looks like this lockless
synchronization pattern might have a race condition.
Because memset() is not atomic, could this zero out the state tracking struct
(which contains idx) before the data buffer is fully cleared?
If a concurrent thread calls smc_wr_tx_get_v2_slot():
if (link->wr_tx_v2_pend->idx == link->wr_tx_cnt)
return -EBUSY;
It checks the idx to locklessly determine slot availability. If idx gets
zeroed early by the first memset(), could the concurrent thread claim the
slot and write new data, only for it to be destroyed by the remainder of
the memset() operations?
For V1 buffers, this appears to be safely handled using a dedicated
link->wr_tx_mask bitmask that is cleared only after the memsets.
[Severity: High]
This is another pre-existing issue in the same file, but could the error
logic in smc_wr_tx_process_cqe() corrupt shared V2 payloads?
smc_wr_tx_process_cqe() {
...
if (wc->status) {
...
if (link->lgr->smc_version == SMC_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));
}
...
}
If a V1 work request completes with an error, the error path unconditionally
zeroes out link->lgr->wr_tx_buf_v2 just because the link group version is
SMC_V2.
Since this buffer is shared across all links within the link group, wouldn't
zeroing it out from a failing link silently corrupt the payload of any
concurrent V2 message on healthy, surviving links in the same group?
> return 1;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260806064252.39180-1-alibuda@linux.alibaba.com?part=1
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-08-07 6:43 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-06 6:42 [PATCH net-next v1 0/2] net/smc: fix v2 slot clearing and reduce TX slot contention D. Wythe
2026-08-06 6:42 ` [PATCH net-next v1 1/2] net/smc: clear the correct v2 slot and buffer in smc_wr_tx_put_slot() D. Wythe
2026-08-07 6:43 ` sashiko-bot
2026-08-06 6:42 ` [PATCH net-next v1 2/2] net/smc: reduce TX slot contention with exclusive wait D. Wythe
2026-08-07 5:45 ` Mahanta Jambigi
2026-08-07 6:43 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox