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. As a result, a nonblocking accept() still succeeds because it checks the accept queue directly, but waiters that sleep for listener readiness can remain asleep until another connection generates a wakeup. This affects poll()/epoll_wait()-based waiters, and can also leave a blocking accept() asleep after migration even though the child is already in the target listener's accept queue. This was observed in a local test where listener A completed the handshake, queued the child, and was closed before userspace called accept(). The child was migrated to listener B, but listener B never received a wakeup for the migrated accept-queue entry. Call READ_ONCE(nsk->sk_data_ready)(nsk) after a successful migration in inet_csk_listen_stop(). The reqsk_timer_handler() path does not need the same change: half-open requests only become readable to userspace when the final ACK completes the handshake, and tcp_child_process() already wakes the listener in that case. Fixes: 54b92e841937 ("tcp: Migrate TCP_ESTABLISHED/TCP_SYN_RECV sockets in accept queues.") Cc: stable@vger.kernel.org Signed-off-by: Zhenzhong Wu --- net/ipv4/inet_connection_sock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 4ac3ae1bc..da1ce082f 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -1483,6 +1483,7 @@ void inet_csk_listen_stop(struct sock *sk) __NET_INC_STATS(sock_net(nsk), LINUX_MIB_TCPMIGRATEREQSUCCESS); reqsk_migrate_reset(req); + READ_ONCE(nsk->sk_data_ready)(nsk); } else { __NET_INC_STATS(sock_net(nsk), LINUX_MIB_TCPMIGRATEREQFAILURE); -- 2.43.0