Commit 5456f09aaf88731e16dbcea7522cb330b6846415
Committed by
David S. Miller
1 parent
67426b756c
Exists in
master
and in
39 other branches
af_unix: fix unix_dgram_poll() behavior for EPOLLOUT event
Alban Crequy reported a problem with connected dgram af_unix sockets and provided a test program. epoll() would miss to send an EPOLLOUT event when a thread unqueues a packet from the other peer, making its receive queue not full. This is because unix_dgram_poll() fails to call sock_poll_wait(file, &unix_sk(other)->peer_wait, wait); if the socket is not writeable at the time epoll_ctl(ADD) is called. We must call sock_poll_wait(), regardless of 'writable' status, so that epoll can be notified later of states changes. Misc: avoids testing twice (sk->sk_shutdown & RCV_SHUTDOWN) Reported-by: Alban Crequy <alban.crequy@collabora.co.uk> Cc: Davide Libenzi <davidel@xmailserver.org> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Acked-by: Davide Libenzi <davidel@xmailserver.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 1 changed file with 9 additions and 15 deletions Side-by-side Diff
net/unix/af_unix.c
... | ... | @@ -2074,13 +2074,12 @@ |
2074 | 2074 | if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) |
2075 | 2075 | mask |= POLLERR; |
2076 | 2076 | if (sk->sk_shutdown & RCV_SHUTDOWN) |
2077 | - mask |= POLLRDHUP; | |
2077 | + mask |= POLLRDHUP | POLLIN | POLLRDNORM; | |
2078 | 2078 | if (sk->sk_shutdown == SHUTDOWN_MASK) |
2079 | 2079 | mask |= POLLHUP; |
2080 | 2080 | |
2081 | 2081 | /* readable? */ |
2082 | - if (!skb_queue_empty(&sk->sk_receive_queue) || | |
2083 | - (sk->sk_shutdown & RCV_SHUTDOWN)) | |
2082 | + if (!skb_queue_empty(&sk->sk_receive_queue)) | |
2084 | 2083 | mask |= POLLIN | POLLRDNORM; |
2085 | 2084 | |
2086 | 2085 | /* Connection-based need to check for termination and startup */ |
2087 | 2086 | |
2088 | 2087 | |
... | ... | @@ -2092,20 +2091,15 @@ |
2092 | 2091 | return mask; |
2093 | 2092 | } |
2094 | 2093 | |
2095 | - /* writable? */ | |
2096 | 2094 | writable = unix_writable(sk); |
2097 | - if (writable) { | |
2098 | - other = unix_peer_get(sk); | |
2099 | - if (other) { | |
2100 | - if (unix_peer(other) != sk) { | |
2101 | - sock_poll_wait(file, &unix_sk(other)->peer_wait, | |
2102 | - wait); | |
2103 | - if (unix_recvq_full(other)) | |
2104 | - writable = 0; | |
2105 | - } | |
2106 | - | |
2107 | - sock_put(other); | |
2095 | + other = unix_peer_get(sk); | |
2096 | + if (other) { | |
2097 | + if (unix_peer(other) != sk) { | |
2098 | + sock_poll_wait(file, &unix_sk(other)->peer_wait, wait); | |
2099 | + if (unix_recvq_full(other)) | |
2100 | + writable = 0; | |
2108 | 2101 | } |
2102 | + sock_put(other); | |
2109 | 2103 | } |
2110 | 2104 | |
2111 | 2105 | if (writable) |