diff options
author | Eric Dumazet <edumazet@google.com> | 2016-12-03 14:14:51 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-12-05 13:32:22 -0500 |
commit | 408f0a6c21e124cc4f6c7aa370b38aa47e55428d (patch) | |
tree | 11a45f9e4e5cfd77e62d1363ad734e6fe753cd91 /net/ipv4/tcp_output.c | |
parent | 40fc3423b983b864bf70b03199191260ae9b2ea6 (diff) |
tcp: tsq: remove one locked operation in tcp_wfree()
Instead of atomically clear TSQ_THROTTLED and atomically set TSQ_QUEUED
bits, use one cmpxchg() to perform a single locked operation.
Since the following patch will also set TCP_TSQ_DEFERRED here,
this cmpxchg() will make this addition free.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_output.c')
-rw-r--r-- | net/ipv4/tcp_output.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 8f0289b0fb24..4adaf8e1bb63 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -860,6 +860,7 @@ void tcp_wfree(struct sk_buff *skb) | |||
860 | { | 860 | { |
861 | struct sock *sk = skb->sk; | 861 | struct sock *sk = skb->sk; |
862 | struct tcp_sock *tp = tcp_sk(sk); | 862 | struct tcp_sock *tp = tcp_sk(sk); |
863 | unsigned long flags, nval, oval; | ||
863 | int wmem; | 864 | int wmem; |
864 | 865 | ||
865 | /* Keep one reference on sk_wmem_alloc. | 866 | /* Keep one reference on sk_wmem_alloc. |
@@ -877,11 +878,17 @@ void tcp_wfree(struct sk_buff *skb) | |||
877 | if (wmem >= SKB_TRUESIZE(1) && this_cpu_ksoftirqd() == current) | 878 | if (wmem >= SKB_TRUESIZE(1) && this_cpu_ksoftirqd() == current) |
878 | goto out; | 879 | goto out; |
879 | 880 | ||
880 | if (test_and_clear_bit(TSQ_THROTTLED, &tp->tsq_flags) && | 881 | for (oval = READ_ONCE(tp->tsq_flags);; oval = nval) { |
881 | !test_and_set_bit(TSQ_QUEUED, &tp->tsq_flags)) { | ||
882 | unsigned long flags; | ||
883 | struct tsq_tasklet *tsq; | 882 | struct tsq_tasklet *tsq; |
884 | 883 | ||
884 | if (!(oval & TSQF_THROTTLED) || (oval & TSQF_QUEUED)) | ||
885 | goto out; | ||
886 | |||
887 | nval = (oval & ~TSQF_THROTTLED) | TSQF_QUEUED; | ||
888 | nval = cmpxchg(&tp->tsq_flags, oval, nval); | ||
889 | if (nval != oval) | ||
890 | continue; | ||
891 | |||
885 | /* queue this socket to tasklet queue */ | 892 | /* queue this socket to tasklet queue */ |
886 | local_irq_save(flags); | 893 | local_irq_save(flags); |
887 | tsq = this_cpu_ptr(&tsq_tasklet); | 894 | tsq = this_cpu_ptr(&tsq_tasklet); |