|
@@ -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,26 +2087,32 @@ 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;
|
|
|
}
|
|
|
|
|
|
if (wq_has_sleeper(&u->peer_wait))
|
|
@@ -2164,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;
|