Merge branch 'akpm' (patches from Andrew)
[cascardo/linux.git] / net / core / dev.c
index 0ef061b..edb7179 100644 (file)
@@ -3829,8 +3829,14 @@ static void net_tx_action(struct softirq_action *h)
                                trace_consume_skb(skb);
                        else
                                trace_kfree_skb(skb, net_tx_action);
-                       __kfree_skb(skb);
+
+                       if (skb->fclone != SKB_FCLONE_UNAVAILABLE)
+                               __kfree_skb(skb);
+                       else
+                               __kfree_skb_defer(skb);
                }
+
+               __kfree_skb_flush();
        }
 
        if (sd->output_queue) {
@@ -4154,7 +4160,10 @@ ncls:
                        ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
        } else {
 drop:
-               atomic_long_inc(&skb->dev->rx_dropped);
+               if (!deliver_exact)
+                       atomic_long_inc(&skb->dev->rx_dropped);
+               else
+                       atomic_long_inc(&skb->dev->rx_nohandler);
                kfree_skb(skb);
                /* Jamal, now you will not able to escape explaining
                 * me how you were going to use this. :-)
@@ -5152,6 +5161,7 @@ static void net_rx_action(struct softirq_action *h)
                }
        }
 
+       __kfree_skb_flush();
        local_irq_disable();
 
        list_splice_tail_init(&sd->poll_list, &list);
@@ -7253,24 +7263,31 @@ void netdev_run_todo(void)
        }
 }
 
-/* Convert net_device_stats to rtnl_link_stats64.  They have the same
- * fields in the same order, with only the type differing.
+/* Convert net_device_stats to rtnl_link_stats64. rtnl_link_stats64 has
+ * all the same fields in the same order as net_device_stats, with only
+ * the type differing, but rtnl_link_stats64 may have additional fields
+ * at the end for newer counters.
  */
 void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64,
                             const struct net_device_stats *netdev_stats)
 {
 #if BITS_PER_LONG == 64
-       BUILD_BUG_ON(sizeof(*stats64) != sizeof(*netdev_stats));
+       BUILD_BUG_ON(sizeof(*stats64) < sizeof(*netdev_stats));
        memcpy(stats64, netdev_stats, sizeof(*stats64));
+       /* zero out counters that only exist in rtnl_link_stats64 */
+       memset((char *)stats64 + sizeof(*netdev_stats), 0,
+              sizeof(*stats64) - sizeof(*netdev_stats));
 #else
-       size_t i, n = sizeof(*stats64) / sizeof(u64);
+       size_t i, n = sizeof(*netdev_stats) / sizeof(unsigned long);
        const unsigned long *src = (const unsigned long *)netdev_stats;
        u64 *dst = (u64 *)stats64;
 
-       BUILD_BUG_ON(sizeof(*netdev_stats) / sizeof(unsigned long) !=
-                    sizeof(*stats64) / sizeof(u64));
+       BUILD_BUG_ON(n > sizeof(*stats64) / sizeof(u64));
        for (i = 0; i < n; i++)
                dst[i] = src[i];
+       /* zero out counters that only exist in rtnl_link_stats64 */
+       memset((char *)stats64 + n * sizeof(u64), 0,
+              sizeof(*stats64) - n * sizeof(u64));
 #endif
 }
 EXPORT_SYMBOL(netdev_stats_to_stats64);
@@ -7300,6 +7317,7 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
        }
        storage->rx_dropped += atomic_long_read(&dev->rx_dropped);
        storage->tx_dropped += atomic_long_read(&dev->tx_dropped);
+       storage->rx_nohandler += atomic_long_read(&dev->rx_nohandler);
        return storage;
 }
 EXPORT_SYMBOL(dev_get_stats);