diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-06-18 11:48:40 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-06-18 11:48:40 -0700 |
commit | d83b14c0db5b238975990c0abda51521120106e9 (patch) | |
tree | 67f27ccfe6dcb37ae07b407b6e6978f18757dba3 /net/unix/af_unix.c | |
parent | 952f4a0a9b27e6dbd5d32e330b3f609ebfa0b061 (diff) | |
parent | 6d1a3fb567a728d31474636e167c324702a0c38b (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (43 commits)
netlink: genl: fix circular locking
Revert "mac80211: Use skb_header_cloned() on TX path."
af_unix: fix 'poll for write'/ connected DGRAM sockets
tun: Proper handling of IPv6 header in tun driver when TUN_NO_PI is set
atl1: relax eeprom mac address error check
net/enc28j60: low power mode
net/enc28j60: section fix
sky2: 88E8040T pci device id
netxen: download firmware in pci probe
netxen: cleanup debug messages
netxen: remove global physical_port array
netxen: fix portnum for hp mezz cards
ibm_newemac: select CRC32 in Kconfig
xfrm: fix fragmentation for ipv4 xfrm tunnel
netfilter: nf_conntrack_h323: fix module unload crash
netfilter: nf_conntrack_h323: fix memory leak in module initialization error path
netfilter: nf_nat: fix RCU races
atm: [he] send idle cells instead of unassigned when in SDH mode
atm: [he] limit queries to the device's register space
atm: [br2864] fix routed vcmux support
...
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) |