diff options
author | Allan Stephens <allan.stephens@windriver.com> | 2010-08-17 11:00:06 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-08-17 17:31:53 -0700 |
commit | f662c07058f7e6365ae65080d772f9122f6f50a9 (patch) | |
tree | 17a8ad3e5e432998d42b25891569f17025cf2b41 /net/tipc | |
parent | 35997e3157eba16c6124d440bdf9272087129b2a (diff) | |
download | linux-f662c07058f7e6365ae65080d772f9122f6f50a9.tar.gz linux-f662c07058f7e6365ae65080d772f9122f6f50a9.tar.bz2 linux-f662c07058f7e6365ae65080d772f9122f6f50a9.zip |
tipc: correct problems with misleading flags returned using poll()
Prevent TIPC from incorrectly setting returned flags to poll()
in the following cases:
- an unconnected socket no longer indicates that it is always readable
- an unconnected, connecting, or listening socket no longer indicates
that it is always writable
Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/socket.c | 61 |
1 files changed, 40 insertions, 21 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index b89c7b1a0d09..7b81fdd4f6d6 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -429,36 +429,55 @@ static int get_name(struct socket *sock, struct sockaddr *uaddr, * to handle any preventable race conditions, so TIPC will do the same ... * * TIPC sets the returned events as follows: - * a) POLLRDNORM and POLLIN are set if the socket's receive queue is non-empty - * or if a connection-oriented socket is does not have an active connection - * (i.e. a read operation will not block). - * b) POLLOUT is set except when a socket's connection has been terminated - * (i.e. a write operation will not block). - * c) POLLHUP is set when a socket's connection has been terminated. - * - * IMPORTANT: The fact that a read or write operation will not block does NOT - * imply that the operation will succeed! + * + * socket state flags set + * ------------ --------- + * unconnected no read flags + * no write flags + * + * connecting POLLIN/POLLRDNORM if ACK/NACK in rx queue + * no write flags + * + * connected POLLIN/POLLRDNORM if data in rx queue + * POLLOUT if port is not congested + * + * disconnecting POLLIN/POLLRDNORM/POLLHUP + * no write flags + * + * listening POLLIN if SYN in rx queue + * no write flags + * + * ready POLLIN/POLLRDNORM if data in rx queue + * [connectionless] POLLOUT (since port cannot be congested) + * + * IMPORTANT: The fact that a read or write operation is indicated does NOT + * imply that the operation will succeed, merely that it should be performed + * and will not block. */ static unsigned int poll(struct file *file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; - u32 mask; + u32 mask = 0; poll_wait(file, sk_sleep(sk), wait); - if (!skb_queue_empty(&sk->sk_receive_queue) || - (sock->state == SS_UNCONNECTED) || - (sock->state == SS_DISCONNECTING)) - mask = (POLLRDNORM | POLLIN); - else - mask = 0; - - if (sock->state == SS_DISCONNECTING) - mask |= POLLHUP; - else - mask |= POLLOUT; + switch ((int)sock->state) { + case SS_READY: + case SS_CONNECTED: + if (!tipc_sk_port(sk)->congested) + mask |= POLLOUT; + /* fall thru' */ + case SS_CONNECTING: + case SS_LISTENING: + if (!skb_queue_empty(&sk->sk_receive_queue)) + mask |= (POLLIN | POLLRDNORM); + break; + case SS_DISCONNECTING: + mask = (POLLIN | POLLRDNORM | POLLHUP); + break; + } return mask; } |