]> git.openfabrics.org - ~emulex/infiniband.git/commitdiff
tipc: correct problems with misleading flags returned using poll()
authorAllan Stephens <allan.stephens@windriver.com>
Tue, 17 Aug 2010 11:00:06 +0000 (11:00 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 18 Aug 2010 00:31:53 +0000 (17:31 -0700)
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>
net/tipc/socket.c

index b89c7b1a0d09c4866ad0f1b741c254a834b1d64c..7b81fdd4f6d6cc8d6dd5e7985e0a946e288c86ac 100644 (file)
@@ -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;
 }