diff -ruN -X dontdiff linux-2.5.38/drivers/net/loopback.c statctr-2.5.38/drivers/net/loopback.c --- linux-2.5.38/drivers/net/loopback.c Sun Sep 22 09:55:01 2002 +++ statctr-2.5.38/drivers/net/loopback.c Wed Sep 25 12:42:15 2002 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -115,13 +116,23 @@ dev_kfree_skb(skb); } +/* Use statctrs for frequently used statistics counters. Using statctr avoids + * in smp. + */ + +struct fast_loopback_stats { + struct statctr rx_bytes; + struct statctr tx_bytes; + struct statctr rx_packets; + struct statctr tx_packets; +} lstats; + /* * The higher levels take care of making this non-reentrant (it's * called with bh's disabled). */ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_device_stats *stats = (struct net_device_stats *)dev->priv; /* * Optimise so buffers with skb->free=1 are not copied but @@ -160,10 +171,10 @@ } dev->last_rx = jiffies; - stats->rx_bytes+=skb->len; - stats->tx_bytes+=skb->len; - stats->rx_packets++; - stats->tx_packets++; + statctr_add(&lstats.rx_bytes, skb->len); + statctr_add(&lstats.tx_bytes, skb->len); + statctr_inc(&lstats.rx_packets); + statctr_inc(&lstats.tx_packets); netif_rx(skb); @@ -172,6 +183,11 @@ static struct net_device_stats *get_stats(struct net_device *dev) { + struct net_device_stats *stats = (struct net_device_stats *)dev->priv; + stats->rx_bytes = statctr_read(&lstats.rx_bytes); + stats->tx_bytes = statctr_read(&lstats.tx_bytes); + stats->rx_packets = statctr_read(&lstats.rx_packets); + stats->tx_packets = statctr_read(&lstats.tx_packets); return (struct net_device_stats *)dev->priv; } @@ -200,6 +216,13 @@ if (dev->priv == NULL) return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_device_stats)); + + if (statctr_ninit(NULL, GFP_KERNEL, 4, &lstats.tx_bytes, + &lstats.rx_bytes, &lstats.tx_packets, + &lstats.rx_packets)) { + kfree(dev->priv); + return -ENOMEM; + } dev->get_stats = get_stats; /*