tipc: fix hanging clients using poll with EPOLLOUT flag
authorParthasarathy Bhuvaragan <parthasarathy.bhuvaragan@gmail.com>
Thu, 9 May 2019 05:13:42 +0000 (07:13 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 9 May 2019 16:26:09 +0000 (09:26 -0700)
commit 517d7c79bdb398 ("tipc: fix hanging poll() for stream sockets")
introduced a regression for clients using non-blocking sockets.
After the commit, we send EPOLLOUT event to the client even in
TIPC_CONNECTING state. This causes the subsequent send() to fail
with ENOTCONN, as the socket is still not in TIPC_ESTABLISHED state.

In this commit, we:
- improve the fix for hanging poll() by replacing sk_data_ready()
  with sk_state_change() to wake up all clients.
- revert the faulty updates introduced by commit 517d7c79bdb398
  ("tipc: fix hanging poll() for stream sockets").

Fixes: 517d7c79bdb398 ("tipc: fix hanging poll() for stream sockets")
Signed-off-by: Parthasarathy Bhuvaragan <parthasarathy.bhuvaragan@gmail.com>
Acked-by: Jon Maloy <jon.maloy@ericsson.se>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/tipc/socket.c

index 145e4decb0c9ab10470e3a4de66a2c046d0c6f70..dd8537f988c4004a5c50e004f1654db5c4e548b6 100644 (file)
@@ -736,11 +736,11 @@ static __poll_t tipc_poll(struct file *file, struct socket *sock,
 
        switch (sk->sk_state) {
        case TIPC_ESTABLISHED:
-       case TIPC_CONNECTING:
                if (!tsk->cong_link_cnt && !tsk_conn_cong(tsk))
                        revents |= EPOLLOUT;
                /* fall through */
        case TIPC_LISTEN:
+       case TIPC_CONNECTING:
                if (!skb_queue_empty(&sk->sk_receive_queue))
                        revents |= EPOLLIN | EPOLLRDNORM;
                break;
@@ -2043,7 +2043,7 @@ static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb)
                        if (msg_data_sz(hdr))
                                return true;
                        /* Empty ACK-, - wake up sleeping connect() and drop */
-                       sk->sk_data_ready(sk);
+                       sk->sk_state_change(sk);
                        msg_set_dest_droppable(hdr, 1);
                        return false;
                }