diff options
Diffstat (limited to 'net/unix/af_unix.c')
| -rw-r--r-- | net/unix/af_unix.c | 79 | 
1 files changed, 70 insertions, 9 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index e18cd3628db..657835f227d 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_datagram_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_datagram_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_datagram_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,64 @@ static unsigned int unix_poll(struct file * file, struct socket *sock, poll_tabl  	return mask;  } +static unsigned int unix_datagram_poll(struct file *file, struct socket *sock, +				       poll_table *wait) +{ +	struct sock *sk = sock->sk, *peer; +	unsigned int mask; + +	poll_wait(file, sk->sk_sleep, wait); + +	peer = unix_peer_get(sk); +	if (peer) { +		if (peer != sk) { +			/* +			 * Writability of a connected socket additionally +			 * depends on the state of the receive queue of the +			 * peer. +			 */ +			poll_wait(file, &unix_sk(peer)->peer_wait, wait); +		} else { +			sock_put(peer); +			peer = NULL; +		} +	} + +	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? */ +	if (unix_writable(sk) && !(peer && unix_recvq_full(peer))) +		mask |= POLLOUT | POLLWRNORM | POLLWRBAND; +	else +		set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + +	if (peer) +		sock_put(peer); + +	return mask; +}  #ifdef CONFIG_PROC_FS  static struct sock *first_unix_socket(int *i)  | 
