]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/unix/af_unix.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[karo-tx-linux.git] / net / unix / af_unix.c
index a4631477cedf94361d3390f8fc616409dc4fcc6c..b1314c0994175f8bc31e7d839e8bec66135c4666 100644 (file)
@@ -451,7 +451,7 @@ static void unix_write_space(struct sock *sk)
        rcu_read_lock();
        if (unix_writable(sk)) {
                wq = rcu_dereference(sk->sk_wq);
-               if (wq_has_sleeper(wq))
+               if (skwq_has_sleeper(wq))
                        wake_up_interruptible_sync_poll(&wq->wait,
                                POLLOUT | POLLWRNORM | POLLWRBAND);
                sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
@@ -2078,8 +2078,8 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg,
        struct scm_cookie scm;
        struct sock *sk = sock->sk;
        struct unix_sock *u = unix_sk(sk);
-       int noblock = flags & MSG_DONTWAIT;
-       struct sk_buff *skb;
+       struct sk_buff *skb, *last;
+       long timeo;
        int err;
        int peeked, skip;
 
@@ -2087,30 +2087,38 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg,
        if (flags&MSG_OOB)
                goto out;
 
-       err = mutex_lock_interruptible(&u->readlock);
-       if (unlikely(err)) {
-               /* recvmsg() in non blocking mode is supposed to return -EAGAIN
-                * sk_rcvtimeo is not honored by mutex_lock_interruptible()
-                */
-               err = noblock ? -EAGAIN : -ERESTARTSYS;
-               goto out;
-       }
+       timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
 
-       skip = sk_peek_offset(sk, flags);
+       do {
+               mutex_lock(&u->readlock);
 
-       skb = __skb_recv_datagram(sk, flags, &peeked, &skip, &err);
-       if (!skb) {
+               skip = sk_peek_offset(sk, flags);
+               skb = __skb_try_recv_datagram(sk, flags, &peeked, &skip, &err,
+                                             &last);
+               if (skb)
+                       break;
+
+               mutex_unlock(&u->readlock);
+
+               if (err != -EAGAIN)
+                       break;
+       } while (timeo &&
+                !__skb_wait_for_more_packets(sk, &err, &timeo, last));
+
+       if (!skb) { /* implies readlock unlocked */
                unix_state_lock(sk);
                /* Signal EOF on disconnected non-blocking SEQPACKET socket. */
                if (sk->sk_type == SOCK_SEQPACKET && err == -EAGAIN &&
                    (sk->sk_shutdown & RCV_SHUTDOWN))
                        err = 0;
                unix_state_unlock(sk);
-               goto out_unlock;
+               goto out;
        }
 
-       wake_up_interruptible_sync_poll(&u->peer_wait,
-                                       POLLOUT | POLLWRNORM | POLLWRBAND);
+       if (wq_has_sleeper(&u->peer_wait))
+               wake_up_interruptible_sync_poll(&u->peer_wait,
+                                               POLLOUT | POLLWRNORM |
+                                               POLLWRBAND);
 
        if (msg->msg_name)
                unix_copy_addr(msg, skb->sk);
@@ -2162,7 +2170,6 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg,
 
 out_free:
        skb_free_datagram(sk, skb);
-out_unlock:
        mutex_unlock(&u->readlock);
 out:
        return err;