aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2009-09-24 06:49:24 -0400
committerDavid S. Miller <davem@davemloft.net>2009-09-30 19:20:38 -0400
commitd99927f4d93f36553699573b279e0ff98ad7dea6 (patch)
tree28481ae5aebac58c5fe29e0f08eddff4e80289f6 /net
parentb7058842c940ad2c08dd829b21e5c92ebe3b8758 (diff)
net: Fix sock_wfree() race
Commit 2b85a34e911bf483c27cfdd124aeb1605145dc80 (net: No more expensive sock_hold()/sock_put() on each tx) opens a window in sock_wfree() where another cpu might free the socket we are working on. A fix is to call sk->sk_write_space(sk) while still holding a reference on sk. Reported-by: Jike Song <albcamus@gmail.com> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/sock.c19
1 files changed, 12 insertions, 7 deletions
diff --git a/net/core/sock.c b/net/core/sock.c
index 77fbfed332e8..7626b6aacd68 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1228,17 +1228,22 @@ void __init sk_init(void)
1228void sock_wfree(struct sk_buff *skb) 1228void sock_wfree(struct sk_buff *skb)
1229{ 1229{
1230 struct sock *sk = skb->sk; 1230 struct sock *sk = skb->sk;
1231 int res; 1231 unsigned int len = skb->truesize;
1232 1232
1233 /* In case it might be waiting for more memory. */ 1233 if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) {
1234 res = atomic_sub_return(skb->truesize, &sk->sk_wmem_alloc); 1234 /*
1235 if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) 1235 * Keep a reference on sk_wmem_alloc, this will be released
1236 * after sk_write_space() call
1237 */
1238 atomic_sub(len - 1, &sk->sk_wmem_alloc);
1236 sk->sk_write_space(sk); 1239 sk->sk_write_space(sk);
1240 len = 1;
1241 }
1237 /* 1242 /*
1238 * if sk_wmem_alloc reached 0, we are last user and should 1243 * if sk_wmem_alloc reaches 0, we must finish what sk_free()
1239 * free this sock, as sk_free() call could not do it. 1244 * could not do because of in-flight packets
1240 */ 1245 */
1241 if (res == 0) 1246 if (atomic_sub_and_test(len, &sk->sk_wmem_alloc))
1242 __sk_free(sk); 1247 __sk_free(sk);
1243} 1248}
1244EXPORT_SYMBOL(sock_wfree); 1249EXPORT_SYMBOL(sock_wfree);