diff options
| author | Allison Henderson <achender@kernel.org> | 2026-08-28 15:39:15 -0700 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-09-02 19:42:23 -0700 |
| commit | 6d0c8b7073913011459cf968cbbadd341e166bc3 (patch) | |
| tree | 39e53a090abe24c871e94b1bfefda11b377f345d | |
| parent | 08710f033e3e35704e45adf8a95b5043ece34899 (diff) | |
net/rds: use wq_has_sleeper() in release_in_xmit()
release_in_xmit() clears RDS_IN_XMIT with clear_bit_unlock() and then
checks waitqueue_active() to decide whether anyone needs waking.
clear_bit_unlock() is only a release operation: it orders the
critical section before the bit clear, but does not order the
subsequent plain load of the wait queue head after it. The waiter
side does the mirror image - it adds itself to the wait queue and
then tests the bit. That is the classic store-buffering pattern: the
releasing CPU can read the wait queue as empty while the waiting CPU
still reads the bit as set, so the sleeper is never woken.
The waiters are rds_conn_shutdown() and rds_tcp_reset_callbacks(),
both in uninterruptible wait_event() with no timeout. A lost wake-up
strands the shutdown worker on its single-threaded workqueue until
some other sender releases the bit again - and on a connection that
is being torn down precisely because it failed, there may never be
another sender.
The barrier used to be there: release_in_xmit() did clear_bit()
followed by smp_mb__after_atomic() until commit 1422f28826d2 ("rds:
introduce acquire/release ordering in acquire/release_in_xmit()")
folded both into clear_bit_unlock(), which strengthened the lock
hand-off but silently dropped the full barrier the wake-up check
depends on. The refill counterpart, release_refill() in
net/rds/ib_recv.c, still carries its smp_mb__after_atomic() for
exactly this reason.
Use wq_has_sleeper(), which is waitqueue_active() preceded by the
required full barrier.
Fixes: 1422f28826d2 ("rds: introduce acquire/release ordering in acquire/release_in_xmit()")
Signed-off-by: Allison Henderson <achender@kernel.org>
Link: https://patch.msgid.link/20260828223921.202913-2-achender@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | net/rds/send.c | 7 |
1 files changed, 6 insertions, 1 deletions
diff --git a/net/rds/send.c b/net/rds/send.c index 15a1b97f13e7..8aad185e4b1a 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -114,8 +114,13 @@ static void release_in_xmit(struct rds_conn_path *cp) * hot path and finding waiters is very rare. We don't want to walk * the system-wide hashed waitqueue buckets in the fast path only to * almost never find waiters. + * + * wq_has_sleeper() supplies the full barrier that orders the wait + * queue read after the bit clear; clear_bit_unlock() alone is only + * a release and would let this check read a stale empty queue, + * losing the wake-up. */ - if (waitqueue_active(&cp->cp_waitq)) + if (wq_has_sleeper(&cp->cp_waitq)) wake_up_all(&cp->cp_waitq); } |
