diff options
Diffstat (limited to 'net/unix/af_unix.c')
| -rw-r--r-- | net/unix/af_unix.c | 75 | 
1 files changed, 66 insertions, 9 deletions
| diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index e18cd3628db4..783317dacd30 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -169,6 +169,11 @@ static inline int unix_may_send(struct sock *sk, struct sock *osk)  	return (unix_peer(osk) == NULL || unix_our_peer(sk, osk));  } +static inline int unix_recvq_full(struct sock const *sk) +{ +	return skb_queue_len(&sk->sk_receive_queue) > sk->sk_max_ack_backlog; +} +  static struct sock *unix_peer_get(struct sock *s)  {  	struct sock *peer; @@ -482,6 +487,8 @@ static int unix_socketpair(struct socket *, struct socket *);  static int unix_accept(struct socket *, struct socket *, int);  static int unix_getname(struct socket *, struct sockaddr *, int *, int);  static unsigned int unix_poll(struct file *, struct socket *, poll_table *); +static unsigned int unix_dgram_poll(struct file *, struct socket *, +				    poll_table *);  static int unix_ioctl(struct socket *, unsigned int, unsigned long);  static int unix_shutdown(struct socket *, int);  static int unix_stream_sendmsg(struct kiocb *, struct socket *, @@ -527,7 +534,7 @@ static const struct proto_ops unix_dgram_ops = {  	.socketpair =	unix_socketpair,  	.accept =	sock_no_accept,  	.getname =	unix_getname, -	.poll =		datagram_poll, +	.poll =		unix_dgram_poll,  	.ioctl =	unix_ioctl,  	.listen =	sock_no_listen,  	.shutdown =	unix_shutdown, @@ -548,7 +555,7 @@ static const struct proto_ops unix_seqpacket_ops = {  	.socketpair =	unix_socketpair,  	.accept =	unix_accept,  	.getname =	unix_getname, -	.poll =		datagram_poll, +	.poll =		unix_dgram_poll,  	.ioctl =	unix_ioctl,  	.listen =	unix_listen,  	.shutdown =	unix_shutdown, @@ -983,8 +990,7 @@ static long unix_wait_for_peer(struct sock *other, long timeo)  	sched = !sock_flag(other, SOCK_DEAD) &&  		!(other->sk_shutdown & RCV_SHUTDOWN) && -		(skb_queue_len(&other->sk_receive_queue) > -		 other->sk_max_ack_backlog); +		unix_recvq_full(other);  	unix_state_unlock(other); @@ -1058,8 +1064,7 @@ restart:  	if (other->sk_state != TCP_LISTEN)  		goto out_unlock; -	if (skb_queue_len(&other->sk_receive_queue) > -	    other->sk_max_ack_backlog) { +	if (unix_recvq_full(other)) {  		err = -EAGAIN;  		if (!timeo)  			goto out_unlock; @@ -1428,9 +1433,7 @@ restart:  			goto out_unlock;  	} -	if (unix_peer(other) != sk && -	    (skb_queue_len(&other->sk_receive_queue) > -	     other->sk_max_ack_backlog)) { +	if (unix_peer(other) != sk && unix_recvq_full(other)) {  		if (!timeo) {  			err = -EAGAIN;  			goto out_unlock; @@ -1991,6 +1994,60 @@ static unsigned int unix_poll(struct file * file, struct socket *sock, poll_tabl  	return mask;  } +static unsigned int unix_dgram_poll(struct file *file, struct socket *sock, +				    poll_table *wait) +{ +	struct sock *sk = sock->sk, *other; +	unsigned int mask, writable; + +	poll_wait(file, sk->sk_sleep, wait); +	mask = 0; + +	/* exceptional events? */ +	if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) +		mask |= POLLERR; +	if (sk->sk_shutdown & RCV_SHUTDOWN) +		mask |= POLLRDHUP; +	if (sk->sk_shutdown == SHUTDOWN_MASK) +		mask |= POLLHUP; + +	/* readable? */ +	if (!skb_queue_empty(&sk->sk_receive_queue) || +	    (sk->sk_shutdown & RCV_SHUTDOWN)) +		mask |= POLLIN | POLLRDNORM; + +	/* Connection-based need to check for termination and startup */ +	if (sk->sk_type == SOCK_SEQPACKET) { +		if (sk->sk_state == TCP_CLOSE) +			mask |= POLLHUP; +		/* connection hasn't started yet? */ +		if (sk->sk_state == TCP_SYN_SENT) +			return mask; +	} + +	/* writable? */ +	writable = unix_writable(sk); +	if (writable) { +		other = unix_peer_get(sk); +		if (other) { +			if (unix_peer(other) != sk) { +				poll_wait(file, &unix_sk(other)->peer_wait, +					  wait); +				if (unix_recvq_full(other)) +					writable = 0; +			} + +			sock_put(other); +		} +	} + +	if (writable) +		mask |= POLLOUT | POLLWRNORM | POLLWRBAND; +	else +		set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + +	return mask; +}  #ifdef CONFIG_PROC_FS  static struct sock *first_unix_socket(int *i) | 
