diff options
author | Li RongQing <roy.qing.li@gmail.com> | 2014-01-02 00:20:12 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-01-02 19:37:21 -0500 |
commit | abb6013cca147ad940b0e9fee260d2d9e93b7018 (patch) | |
tree | 58ff3dd11e53ec545df209e5b386dcdd094228bc /net/ipv6/ip6_tunnel.c | |
parent | fad8da3e085ddf5e661090033287f1a5d62858fc (diff) |
ipv6: fix the use of pcpu_tstats in ip6_tunnel
when read/write the 64bit data, the correct lock should be hold.
Fixes: 87b6d218f3adb ("tunnel: implement 64 bits statistics")
Cc: Stephen Hemminger <stephen@networkplumber.org>
Cc: Eric Dumazet <edumazet@google.com>
Signed-off-by: Li RongQing <roy.qing.li@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/ip6_tunnel.c')
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index d6062325db08..7881965a8248 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -103,16 +103,25 @@ struct ip6_tnl_net { | |||
103 | 103 | ||
104 | static struct net_device_stats *ip6_get_stats(struct net_device *dev) | 104 | static struct net_device_stats *ip6_get_stats(struct net_device *dev) |
105 | { | 105 | { |
106 | struct pcpu_tstats sum = { 0 }; | 106 | struct pcpu_tstats tmp, sum = { 0 }; |
107 | int i; | 107 | int i; |
108 | 108 | ||
109 | for_each_possible_cpu(i) { | 109 | for_each_possible_cpu(i) { |
110 | unsigned int start; | ||
110 | const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i); | 111 | const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i); |
111 | 112 | ||
112 | sum.rx_packets += tstats->rx_packets; | 113 | do { |
113 | sum.rx_bytes += tstats->rx_bytes; | 114 | start = u64_stats_fetch_begin_bh(&tstats->syncp); |
114 | sum.tx_packets += tstats->tx_packets; | 115 | tmp.rx_packets = tstats->rx_packets; |
115 | sum.tx_bytes += tstats->tx_bytes; | 116 | tmp.rx_bytes = tstats->rx_bytes; |
117 | tmp.tx_packets = tstats->tx_packets; | ||
118 | tmp.tx_bytes = tstats->tx_bytes; | ||
119 | } while (u64_stats_fetch_retry_bh(&tstats->syncp, start)); | ||
120 | |||
121 | sum.rx_packets += tmp.rx_packets; | ||
122 | sum.rx_bytes += tmp.rx_bytes; | ||
123 | sum.tx_packets += tmp.tx_packets; | ||
124 | sum.tx_bytes += tmp.tx_bytes; | ||
116 | } | 125 | } |
117 | dev->stats.rx_packets = sum.rx_packets; | 126 | dev->stats.rx_packets = sum.rx_packets; |
118 | dev->stats.rx_bytes = sum.rx_bytes; | 127 | dev->stats.rx_bytes = sum.rx_bytes; |
@@ -824,8 +833,10 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, | |||
824 | } | 833 | } |
825 | 834 | ||
826 | tstats = this_cpu_ptr(t->dev->tstats); | 835 | tstats = this_cpu_ptr(t->dev->tstats); |
836 | u64_stats_update_begin(&tstats->syncp); | ||
827 | tstats->rx_packets++; | 837 | tstats->rx_packets++; |
828 | tstats->rx_bytes += skb->len; | 838 | tstats->rx_bytes += skb->len; |
839 | u64_stats_update_end(&tstats->syncp); | ||
829 | 840 | ||
830 | netif_rx(skb); | 841 | netif_rx(skb); |
831 | 842 | ||