aboutsummaryrefslogtreecommitdiffstats
path: root/net/8021q/vlan_core.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2009-11-17 04:53:09 +0000
committerDavid S. Miller <davem@davemloft.net>2009-11-17 23:51:55 -0800
commit9793241fe92f7d9303fb221e43fc598eb065f267 (patch)
tree5f7a347c3a6b32a49e54f1f6ead1c96f2351208c /net/8021q/vlan_core.c
parentd83345adf96bc13a5e360f4649a2e68ef968dec0 (diff)
downloadkernel_samsung_aries-9793241fe92f7d9303fb221e43fc598eb065f267.zip
kernel_samsung_aries-9793241fe92f7d9303fb221e43fc598eb065f267.tar.gz
kernel_samsung_aries-9793241fe92f7d9303fb221e43fc598eb065f267.tar.bz2
vlan: Precise RX stats accounting
With multi queue devices, its possible that several cpus call vlan RX routines simultaneously for the same vlan device. We update RX stats counter without any locking, so we can get slightly wrong counters. One possible fix is to use percpu counters, to get precise accounting and also get guarantee of no cache line ping pongs between cpus. Note: this adds 16 bytes (32 bytes on 64bit arches) of percpu data per vlan device. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/8021q/vlan_core.c')
-rw-r--r--net/8021q/vlan_core.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index 971d375..e75a2f3 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -31,7 +31,7 @@ EXPORT_SYMBOL(__vlan_hwaccel_rx);
int vlan_hwaccel_do_receive(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
- struct net_device_stats *stats;
+ struct vlan_rx_stats *rx_stats;
skb->dev = vlan_dev_info(dev)->real_dev;
netif_nit_deliver(skb);
@@ -40,15 +40,17 @@ int vlan_hwaccel_do_receive(struct sk_buff *skb)
skb->priority = vlan_get_ingress_priority(dev, skb->vlan_tci);
skb->vlan_tci = 0;
- stats = &dev->stats;
- stats->rx_packets++;
- stats->rx_bytes += skb->len;
+ rx_stats = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats,
+ smp_processor_id());
+
+ rx_stats->rx_packets++;
+ rx_stats->rx_bytes += skb->len;
switch (skb->pkt_type) {
case PACKET_BROADCAST:
break;
case PACKET_MULTICAST:
- stats->multicast++;
+ rx_stats->multicast++;
break;
case PACKET_OTHERHOST:
/* Our lower layer thinks this is not local, let's make sure.