|
@@ -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);
|