On Tue, Apr 21, 2026 at 5:31 AM Zhenzhong Wu <[email protected]> wrote: > > When inet_csk_listen_stop() migrates an established child socket from > a closing listener to another socket in the same SO_REUSEPORT group, > the target listener gets a new accept-queue entry via > inet_csk_reqsk_queue_add(), but that path never notifies the target > listener's waiters. A nonblocking accept() still works because it > checks the queue directly, but poll()/epoll_wait() waiters and > blocking accept() callers can also remain asleep indefinitely. > > Call READ_ONCE(nsk->sk_data_ready)(nsk) after a successful migration > in inet_csk_listen_stop(). > > However, after inet_csk_reqsk_queue_add() succeeds, the ref acquired > in reuseport_migrate_sock() is effectively transferred to > nreq->rsk_listener. Another CPU can then dequeue nreq via accept() > or listener shutdown, hit reqsk_put(), and drop that listener ref. > Since listeners are SOCK_RCU_FREE, wrap the post-queue_add() > dereferences of nsk in rcu_read_lock()/rcu_read_unlock(), which also > covers the existing sock_net(nsk) access in that path. > > The reqsk_timer_handler() path does not need the same changes for two > reasons: half-open requests become readable only after the final ACK, > where tcp_child_process() already wakes the listener; and once nreq is > visible via inet_ehash_insert(), the success path no longer touches > nsk directly. > > Fixes: 54b92e841937 ("tcp: Migrate TCP_ESTABLISHED/TCP_SYN_RECV sockets in > accept queues.") > Cc: [email protected] > Suggested-by: Eric Dumazet <[email protected]> > Signed-off-by: Zhenzhong Wu <[email protected]>
Reviewed-by: Kuniyuki Iwashima <[email protected]>

