Skip to content

Commit

Permalink
net: sk_wmem_alloc has initial value of one, not zero
Browse files Browse the repository at this point in the history
commit 2b85a34
(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 <[email protected]>
Signed-off-by: Eric Dumazet <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Eric Dumazet authored and davem330 committed Jun 17, 2009
1 parent 1d4ac5d commit c564039
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 16 deletions.
33 changes: 33 additions & 0 deletions include/net/sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -1206,6 +1206,39 @@ static inline int skb_copy_to_page(struct sock *sk, char __user *from,
return 0;
}

/**
* sk_wmem_alloc_get - returns write allocations
* @sk: socket
*
* Returns sk_wmem_alloc minus initial offset of one
*/
static inline int sk_wmem_alloc_get(const struct sock *sk)
{
return atomic_read(&sk->sk_wmem_alloc) - 1;
}

/**
* sk_rmem_alloc_get - returns read allocations
* @sk: socket
*
* Returns sk_rmem_alloc
*/
static inline int sk_rmem_alloc_get(const struct sock *sk)
{
return atomic_read(&sk->sk_rmem_alloc);
}

/**
* sk_has_allocations - check if allocations are outstanding
* @sk: socket
*
* Returns true if socket has write or read allocations
*/
static inline int sk_has_allocations(const struct sock *sk)
{
return sk_wmem_alloc_get(sk) || sk_rmem_alloc_get(sk);
}

/*
* Queue a received datagram if it will fit. Stream and sequenced
* protocols can't normally use this as they need to fit buffers in
Expand Down
6 changes: 2 additions & 4 deletions net/appletalk/ddp.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,7 @@ static void atalk_destroy_timer(unsigned long data)
{
struct sock *sk = (struct sock *)data;

if (atomic_read(&sk->sk_wmem_alloc) ||
atomic_read(&sk->sk_rmem_alloc)) {
if (sk_has_allocations(sk)) {
sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME;
add_timer(&sk->sk_timer);
} else
Expand All @@ -175,8 +174,7 @@ static inline void atalk_destroy_socket(struct sock *sk)
atalk_remove_socket(sk);
skb_queue_purge(&sk->sk_receive_queue);

if (atomic_read(&sk->sk_wmem_alloc) ||
atomic_read(&sk->sk_rmem_alloc)) {
if (sk_has_allocations(sk)) {
setup_timer(&sk->sk_timer, atalk_destroy_timer,
(unsigned long)sk);
sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME;
Expand Down
3 changes: 1 addition & 2 deletions net/ax25/af_ax25.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,7 @@ void ax25_destroy_socket(ax25_cb *ax25)
}

if (ax25->sk != NULL) {
if (atomic_read(&ax25->sk->sk_wmem_alloc) ||
atomic_read(&ax25->sk->sk_rmem_alloc)) {
if (sk_has_allocations(ax25->sk)) {
/* Defer: outstanding buffers */
setup_timer(&ax25->dtimer, ax25_destroy_timer,
(unsigned long)ax25);
Expand Down
6 changes: 2 additions & 4 deletions net/econet/af_econet.c
Original file line number Diff line number Diff line change
Expand Up @@ -540,8 +540,7 @@ static void econet_destroy_timer(unsigned long data)
{
struct sock *sk=(struct sock *)data;

if (!atomic_read(&sk->sk_wmem_alloc) &&
!atomic_read(&sk->sk_rmem_alloc)) {
if (!sk_has_allocations(sk)) {
sk_free(sk);
return;
}
Expand Down Expand Up @@ -579,8 +578,7 @@ static int econet_release(struct socket *sock)

skb_queue_purge(&sk->sk_receive_queue);

if (atomic_read(&sk->sk_rmem_alloc) ||
atomic_read(&sk->sk_wmem_alloc)) {
if (sk_has_allocations(sk)) {
sk->sk_timer.data = (unsigned long)sk;
sk->sk_timer.expires = jiffies + HZ;
sk->sk_timer.function = econet_destroy_timer;
Expand Down
3 changes: 1 addition & 2 deletions net/netrom/af_netrom.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,7 @@ void nr_destroy_socket(struct sock *sk)
kfree_skb(skb);
}

if (atomic_read(&sk->sk_wmem_alloc) ||
atomic_read(&sk->sk_rmem_alloc)) {
if (sk_has_allocations(sk)) {
/* Defer: outstanding buffers */
sk->sk_timer.function = nr_destroy_timer;
sk->sk_timer.expires = jiffies + 2 * HZ;
Expand Down
3 changes: 1 addition & 2 deletions net/rose/af_rose.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,8 +356,7 @@ void rose_destroy_socket(struct sock *sk)
kfree_skb(skb);
}

if (atomic_read(&sk->sk_wmem_alloc) ||
atomic_read(&sk->sk_rmem_alloc)) {
if (sk_has_allocations(sk)) {
/* Defer: outstanding buffers */
setup_timer(&sk->sk_timer, rose_destroy_timer,
(unsigned long)sk);
Expand Down
3 changes: 1 addition & 2 deletions net/x25/af_x25.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,7 @@ static void __x25_destroy_socket(struct sock *sk)
kfree_skb(skb);
}

if (atomic_read(&sk->sk_wmem_alloc) ||
atomic_read(&sk->sk_rmem_alloc)) {
if (sk_has_allocations(sk)) {
/* Defer: outstanding buffers */
sk->sk_timer.expires = jiffies + 10 * HZ;
sk->sk_timer.function = x25_destroy_timer;
Expand Down

0 comments on commit c564039

Please sign in to comment.