diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-30 17:36:45 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-30 17:36:45 -0700 |
commit | 817b33d38f81c8736d39283c35c886ae4668f1af (patch) | |
tree | 64f60a88baf8b48c350d680f8b69fa6c759c3a82 /net/core/sock.c | |
parent | 84d88d5d4efc37dfb8a93a4a58d8a227ee86ffa4 (diff) | |
parent | 8c185ab6185bf5e67766edb000ce428269364c86 (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:
ax25: Fix possible oops in ax25_make_new
net: restore tx timestamping for accelerated vlans
Phonet: fix mutex imbalance
sit: fix off-by-one in ipip6_tunnel_get_prl
net: Fix sock_wfree() race
net: Make setsockopt() optlen be unsigned.
Diffstat (limited to 'net/core/sock.c')
-rw-r--r-- | net/core/sock.c | 27 |
1 files changed, 16 insertions, 11 deletions
diff --git a/net/core/sock.c b/net/core/sock.c index 524712a7b15..7626b6aacd6 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -446,7 +446,7 @@ static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool) */ int sock_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; int val; @@ -1228,17 +1228,22 @@ void __init sk_init(void) void sock_wfree(struct sk_buff *skb) { struct sock *sk = skb->sk; - int res; + unsigned int len = skb->truesize; - /* In case it might be waiting for more memory. */ - res = atomic_sub_return(skb->truesize, &sk->sk_wmem_alloc); - if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) + if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) { + /* + * Keep a reference on sk_wmem_alloc, this will be released + * after sk_write_space() call + */ + atomic_sub(len - 1, &sk->sk_wmem_alloc); sk->sk_write_space(sk); + len = 1; + } /* - * if sk_wmem_alloc reached 0, we are last user and should - * free this sock, as sk_free() call could not do it. + * if sk_wmem_alloc reaches 0, we must finish what sk_free() + * could not do because of in-flight packets */ - if (res == 0) + if (atomic_sub_and_test(len, &sk->sk_wmem_alloc)) __sk_free(sk); } EXPORT_SYMBOL(sock_wfree); @@ -1697,7 +1702,7 @@ int sock_no_shutdown(struct socket *sock, int how) EXPORT_SYMBOL(sock_no_shutdown); int sock_no_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { return -EOPNOTSUPP; } @@ -2018,7 +2023,7 @@ EXPORT_SYMBOL(sock_common_recvmsg); * Set socket options on an inet socket. */ int sock_common_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; @@ -2028,7 +2033,7 @@ EXPORT_SYMBOL(sock_common_setsockopt); #ifdef CONFIG_COMPAT int compat_sock_common_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; |