X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=drivers%2Fnet%2Floopback.c;h=6ba6ed2b480add4ec4d37fbdf2c1653997376c78;hb=3cb7396b7b26585b1ab7c1a8ca554ec103da5d37;hp=4178b4b1d2df544a5b7c20fe90a0c0b02727ddcf;hpb=82965addad66fce61a92c5f03104ea90b0b87124;p=powerpc.git diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 4178b4b1d2..6ba6ed2b48 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -58,7 +58,11 @@ #include #include -static DEFINE_PER_CPU(struct net_device_stats, loopback_stats); +struct pcpu_lstats { + unsigned long packets; + unsigned long bytes; +}; +static DEFINE_PER_CPU(struct pcpu_lstats, pcpu_lstats); #define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16) @@ -71,8 +75,9 @@ static DEFINE_PER_CPU(struct net_device_stats, loopback_stats); #ifdef LOOPBACK_TSO static void emulate_large_send_offload(struct sk_buff *skb) { - struct iphdr *iph = skb->nh.iph; - struct tcphdr *th = (struct tcphdr*)(skb->nh.raw + (iph->ihl * 4)); + struct iphdr *iph = ip_hdr(skb); + struct tcphdr *th = (struct tcphdr *)(skb_network_header(skb) + + (iph->ihl * 4)); unsigned int doffset = (iph->ihl + th->doff) * 4; unsigned int mtu = skb_shinfo(skb)->gso_size + doffset; unsigned int offset = 0; @@ -86,10 +91,11 @@ static void emulate_large_send_offload(struct sk_buff *skb) if (!nskb) break; skb_reserve(nskb, 32); - nskb->mac.raw = nskb->data - 14; - nskb->nh.raw = nskb->data; - iph = nskb->nh.iph; - memcpy(nskb->data, skb->nh.raw, doffset); + skb_set_mac_header(nskb, -ETH_HLEN); + skb_reset_network_header(nskb); + iph = ip_hdr(nskb); + skb_copy_to_linear_data(nskb, skb_network_header(skb), + doffset); if (skb_copy_bits(skb, doffset + offset, nskb->data + doffset, @@ -104,7 +110,7 @@ static void emulate_large_send_offload(struct sk_buff *skb) memcpy(nskb->cb, skb->cb, sizeof(skb->cb)); nskb->pkt_type = skb->pkt_type; - th = (struct tcphdr*)(nskb->nh.raw + iph->ihl*4); + th = (struct tcphdr *)(skb_network_header(nskb) + iph->ihl * 4); iph->tot_len = htons(frag_size + doffset); iph->id = htons(id); iph->check = 0; @@ -128,12 +134,11 @@ static void emulate_large_send_offload(struct sk_buff *skb) */ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_device_stats *lb_stats; + struct pcpu_lstats *lb_stats; skb_orphan(skb); skb->protocol = eth_type_trans(skb,dev); - skb->dev = dev; #ifndef LOOPBACK_MUST_CHECKSUM skb->ip_summed = CHECKSUM_UNNECESSARY; #endif @@ -141,7 +146,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) #ifdef LOOPBACK_TSO if (skb_is_gso(skb)) { BUG_ON(skb->protocol != htons(ETH_P_IP)); - BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP); + BUG_ON(ip_hdr(skb)->protocol != IPPROTO_TCP); emulate_large_send_offload(skb); return 0; @@ -149,37 +154,34 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) #endif dev->last_rx = jiffies; - lb_stats = &per_cpu(loopback_stats, get_cpu()); - lb_stats->rx_bytes += skb->len; - lb_stats->tx_bytes = lb_stats->rx_bytes; - lb_stats->rx_packets++; - lb_stats->tx_packets = lb_stats->rx_packets; - put_cpu(); + /* it's OK to use __get_cpu_var() because BHs are off */ + lb_stats = &__get_cpu_var(pcpu_lstats); + lb_stats->bytes += skb->len; + lb_stats->packets++; netif_rx(skb); - return(0); + return 0; } -static struct net_device_stats loopback_stats; - static struct net_device_stats *get_stats(struct net_device *dev) { - struct net_device_stats *stats = &loopback_stats; + struct net_device_stats *stats = &dev->stats; + unsigned long bytes = 0; + unsigned long packets = 0; int i; - memset(stats, 0, sizeof(struct net_device_stats)); - for_each_possible_cpu(i) { - struct net_device_stats *lb_stats; + const struct pcpu_lstats *lb_stats; - lb_stats = &per_cpu(loopback_stats, i); - stats->rx_bytes += lb_stats->rx_bytes; - stats->tx_bytes += lb_stats->tx_bytes; - stats->rx_packets += lb_stats->rx_packets; - stats->tx_packets += lb_stats->tx_packets; + lb_stats = &per_cpu(pcpu_lstats, i); + bytes += lb_stats->bytes; + packets += lb_stats->packets; } - + stats->rx_packets = packets; + stats->tx_packets = packets; + stats->rx_bytes = bytes; + stats->tx_bytes = bytes; return stats; } @@ -204,7 +206,6 @@ static const struct ethtool_ops loopback_ethtool_ops = { struct net_device loopback_dev = { .name = "lo", .get_stats = &get_stats, - .priv = &loopback_stats, .mtu = (16 * 1024) + 20 + 20 + 12, .hard_start_xmit = loopback_xmit, .hard_header = eth_header, @@ -226,9 +227,11 @@ struct net_device loopback_dev = { }; /* Setup and register the loopback device. */ -int __init loopback_init(void) +static int __init loopback_init(void) { return register_netdev(&loopback_dev); }; +module_init(loopback_init); + EXPORT_SYMBOL(loopback_dev);