tipc: Optimize tipc_node_has_active_links()
[pandora-kernel.git] / net / tipc / socket.c
index 66e889b..7b81fdd 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;
 }
@@ -1026,9 +1045,8 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
        struct sk_buff *buf;
        struct tipc_msg *msg;
        unsigned int sz;
-       int sz_to_copy;
+       int sz_to_copy, target, needed;
        int sz_copied = 0;
-       int needed;
        char __user *crs = m->msg_iov->iov_base;
        unsigned char *buf_crs;
        u32 err;
@@ -1050,6 +1068,8 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
                goto exit;
        }
 
+       target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len);
+
 restart:
 
        /* Look for a message in receive queue; wait if necessary */
@@ -1138,7 +1158,7 @@ restart:
 
        if ((sz_copied < buf_len) &&    /* didn't get all requested data */
            (!skb_queue_empty(&sk->sk_receive_queue) ||
-            (flags & MSG_WAITALL)) &&  /* and more is ready or required */
+           (sz_copied < target)) &&    /* and more is ready or required */
            (!(flags & MSG_PEEK)) &&    /* and aren't just peeking at data */
            (!err))                     /* and haven't reached a FIN */
                goto restart;
@@ -1379,7 +1399,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
        /* For now, TIPC does not support the non-blocking form of connect() */
 
        if (flags & O_NONBLOCK) {
-               res = -EWOULDBLOCK;
+               res = -EOPNOTSUPP;
                goto exit;
        }