aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2009-06-16 06:12:03 -0400
committerDavid S. Miller <davem@davemloft.net>2009-06-17 07:31:25 -0400
commitc564039fd83ea16a86a96d52632794b24849e507 (patch)
tree42c9f525d08ea2e7d36c0231cc628587a175a39b
parent1d4ac5d5ef9dd965ae211ebe8acbf83dc4d9571b (diff)
net: sk_wmem_alloc has initial value of one, not zero
commit 2b85a34e911bf483c27cfdd124aeb1605145dc80 (net: No more expensive sock_hold()/sock_put() on each tx) changed initial sk_wmem_alloc value. Some protocols check sk_wmem_alloc value to determine if a timer must delay socket deallocation. We must take care of the sk_wmem_alloc value being one instead of zero when no write allocations are pending. Reported by Ingo Molnar, and full diagnostic from David Miller. This patch introduces three helpers to get read/write allocations and a followup patch will use these helpers to report correct write allocations to user. Reported-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/sock.h33
-rw-r--r--net/appletalk/ddp.c6
-rw-r--r--net/ax25/af_ax25.c3
-rw-r--r--net/econet/af_econet.c6
-rw-r--r--net/netrom/af_netrom.c3
-rw-r--r--net/rose/af_rose.c3
-rw-r--r--net/x25/af_x25.c3
7 files changed, 41 insertions, 16 deletions
diff --git a/include/net/sock.h b/include/net/sock.h
index 010e14a93c92..570c7a12b54e 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1206,6 +1206,39 @@ static inline int skb_copy_to_page(struct sock *sk, char __user *from,
1206 return 0; 1206 return 0;
1207} 1207}
1208 1208
1209/**
1210 * sk_wmem_alloc_get - returns write allocations
1211 * @sk: socket
1212 *
1213 * Returns sk_wmem_alloc minus initial offset of one
1214 */
1215static inline int sk_wmem_alloc_get(const struct sock *sk)
1216{
1217 return atomic_read(&sk->sk_wmem_alloc) - 1;
1218}
1219
1220/**
1221 * sk_rmem_alloc_get - returns read allocations
1222 * @sk: socket
1223 *
1224 * Returns sk_rmem_alloc
1225 */
1226static inline int sk_rmem_alloc_get(const struct sock *sk)
1227{
1228 return atomic_read(&sk->sk_rmem_alloc);
1229}
1230
1231/**
1232 * sk_has_allocations - check if allocations are outstanding
1233 * @sk: socket
1234 *
1235 * Returns true if socket has write or read allocations
1236 */
1237static inline int sk_has_allocations(const struct sock *sk)
1238{
1239 return sk_wmem_alloc_get(sk) || sk_rmem_alloc_get(sk);
1240}
1241
1209/* 1242/*
1210 * Queue a received datagram if it will fit. Stream and sequenced 1243 * Queue a received datagram if it will fit. Stream and sequenced
1211 * protocols can't normally use this as they need to fit buffers in 1244 * protocols can't normally use this as they need to fit buffers in
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index b603cbacdc58..f7a53b219ef0 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -162,8 +162,7 @@ static void atalk_destroy_timer(unsigned long data)
162{ 162{
163 struct sock *sk = (struct sock *)data; 163 struct sock *sk = (struct sock *)data;
164 164
165 if (atomic_read(&sk->sk_wmem_alloc) || 165 if (sk_has_allocations(sk)) {
166 atomic_read(&sk->sk_rmem_alloc)) {
167 sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME; 166 sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME;
168 add_timer(&sk->sk_timer); 167 add_timer(&sk->sk_timer);
169 } else 168 } else
@@ -175,8 +174,7 @@ static inline void atalk_destroy_socket(struct sock *sk)
175 atalk_remove_socket(sk); 174 atalk_remove_socket(sk);
176 skb_queue_purge(&sk->sk_receive_queue); 175 skb_queue_purge(&sk->sk_receive_queue);
177 176
178 if (atomic_read(&sk->sk_wmem_alloc) || 177 if (sk_has_allocations(sk)) {
179 atomic_read(&sk->sk_rmem_alloc)) {
180 setup_timer(&sk->sk_timer, atalk_destroy_timer, 178 setup_timer(&sk->sk_timer, atalk_destroy_timer,
181 (unsigned long)sk); 179 (unsigned long)sk);
182 sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME; 180 sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME;
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index fd9d06f291dc..61b35b955490 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -330,8 +330,7 @@ void ax25_destroy_socket(ax25_cb *ax25)
330 } 330 }
331 331
332 if (ax25->sk != NULL) { 332 if (ax25->sk != NULL) {
333 if (atomic_read(&ax25->sk->sk_wmem_alloc) || 333 if (sk_has_allocations(ax25->sk)) {
334 atomic_read(&ax25->sk->sk_rmem_alloc)) {
335 /* Defer: outstanding buffers */ 334 /* Defer: outstanding buffers */
336 setup_timer(&ax25->dtimer, ax25_destroy_timer, 335 setup_timer(&ax25->dtimer, ax25_destroy_timer,
337 (unsigned long)ax25); 336 (unsigned long)ax25);
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index 8121bf0029e3..2e1f836d4240 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -540,8 +540,7 @@ static void econet_destroy_timer(unsigned long data)
540{ 540{
541 struct sock *sk=(struct sock *)data; 541 struct sock *sk=(struct sock *)data;
542 542
543 if (!atomic_read(&sk->sk_wmem_alloc) && 543 if (!sk_has_allocations(sk)) {
544 !atomic_read(&sk->sk_rmem_alloc)) {
545 sk_free(sk); 544 sk_free(sk);
546 return; 545 return;
547 } 546 }
@@ -579,8 +578,7 @@ static int econet_release(struct socket *sock)
579 578
580 skb_queue_purge(&sk->sk_receive_queue); 579 skb_queue_purge(&sk->sk_receive_queue);
581 580
582 if (atomic_read(&sk->sk_rmem_alloc) || 581 if (sk_has_allocations(sk)) {
583 atomic_read(&sk->sk_wmem_alloc)) {
584 sk->sk_timer.data = (unsigned long)sk; 582 sk->sk_timer.data = (unsigned long)sk;
585 sk->sk_timer.expires = jiffies + HZ; 583 sk->sk_timer.expires = jiffies + HZ;
586 sk->sk_timer.function = econet_destroy_timer; 584 sk->sk_timer.function = econet_destroy_timer;
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 3be0e016ab7d..cd911904cbe1 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -286,8 +286,7 @@ void nr_destroy_socket(struct sock *sk)
286 kfree_skb(skb); 286 kfree_skb(skb);
287 } 287 }
288 288
289 if (atomic_read(&sk->sk_wmem_alloc) || 289 if (sk_has_allocations(sk)) {
290 atomic_read(&sk->sk_rmem_alloc)) {
291 /* Defer: outstanding buffers */ 290 /* Defer: outstanding buffers */
292 sk->sk_timer.function = nr_destroy_timer; 291 sk->sk_timer.function = nr_destroy_timer;
293 sk->sk_timer.expires = jiffies + 2 * HZ; 292 sk->sk_timer.expires = jiffies + 2 * HZ;
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 877a7f65f707..4dd9a7d18945 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -356,8 +356,7 @@ void rose_destroy_socket(struct sock *sk)
356 kfree_skb(skb); 356 kfree_skb(skb);
357 } 357 }
358 358
359 if (atomic_read(&sk->sk_wmem_alloc) || 359 if (sk_has_allocations(sk)) {
360 atomic_read(&sk->sk_rmem_alloc)) {
361 /* Defer: outstanding buffers */ 360 /* Defer: outstanding buffers */
362 setup_timer(&sk->sk_timer, rose_destroy_timer, 361 setup_timer(&sk->sk_timer, rose_destroy_timer,
363 (unsigned long)sk); 362 (unsigned long)sk);
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index c51f3095739c..8cd2390b0d45 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -372,8 +372,7 @@ static void __x25_destroy_socket(struct sock *sk)
372 kfree_skb(skb); 372 kfree_skb(skb);
373 } 373 }
374 374
375 if (atomic_read(&sk->sk_wmem_alloc) || 375 if (sk_has_allocations(sk)) {
376 atomic_read(&sk->sk_rmem_alloc)) {
377 /* Defer: outstanding buffers */ 376 /* Defer: outstanding buffers */
378 sk->sk_timer.expires = jiffies + 10 * HZ; 377 sk->sk_timer.expires = jiffies + 10 * HZ;
379 sk->sk_timer.function = x25_destroy_timer; 378 sk->sk_timer.function = x25_destroy_timer;