Upgrade to 4.4.50-rt62
[kvmfornfv.git] / kernel / net / core / dev.c
index 0e17592..aa6165e 100644 (file)
@@ -1682,24 +1682,19 @@ EXPORT_SYMBOL_GPL(net_dec_ingress_queue);
 
 static struct static_key netstamp_needed __read_mostly;
 #ifdef HAVE_JUMP_LABEL
-/* We are not allowed to call static_key_slow_dec() from irq context
- * If net_disable_timestamp() is called from irq context, defer the
- * static_key_slow_dec() calls.
- */
 static atomic_t netstamp_needed_deferred;
-#endif
-
-void net_enable_timestamp(void)
+static void netstamp_clear(struct work_struct *work)
 {
-#ifdef HAVE_JUMP_LABEL
        int deferred = atomic_xchg(&netstamp_needed_deferred, 0);
 
-       if (deferred) {
-               while (--deferred)
-                       static_key_slow_dec(&netstamp_needed);
-               return;
-       }
+       while (deferred--)
+               static_key_slow_dec(&netstamp_needed);
+}
+static DECLARE_WORK(netstamp_work, netstamp_clear);
 #endif
+
+void net_enable_timestamp(void)
+{
        static_key_slow_inc(&netstamp_needed);
 }
 EXPORT_SYMBOL(net_enable_timestamp);
@@ -1707,12 +1702,12 @@ EXPORT_SYMBOL(net_enable_timestamp);
 void net_disable_timestamp(void)
 {
 #ifdef HAVE_JUMP_LABEL
-       if (in_interrupt()) {
-               atomic_inc(&netstamp_needed_deferred);
-               return;
-       }
-#endif
+       /* net_disable_timestamp() can be called from non process context */
+       atomic_inc(&netstamp_needed_deferred);
+       schedule_work(&netstamp_work);
+#else
        static_key_slow_dec(&netstamp_needed);
+#endif
 }
 EXPORT_SYMBOL(net_disable_timestamp);
 
@@ -2470,7 +2465,7 @@ int skb_checksum_help(struct sk_buff *skb)
                        goto out;
        }
 
-       *(__sum16 *)(skb->data + offset) = csum_fold(csum);
+       *(__sum16 *)(skb->data + offset) = csum_fold(csum) ?: CSUM_MANGLED_0;
 out_set_summed:
        skb->ip_summed = CHECKSUM_NONE;
 out:
@@ -2658,9 +2653,9 @@ static netdev_features_t harmonize_features(struct sk_buff *skb,
        if (skb->ip_summed != CHECKSUM_NONE &&
            !can_checksum_protocol(features, type)) {
                features &= ~NETIF_F_ALL_CSUM;
-       } else if (illegal_highdma(skb->dev, skb)) {
-               features &= ~NETIF_F_SG;
        }
+       if (illegal_highdma(skb->dev, skb))
+               features &= ~NETIF_F_SG;
 
        return features;
 }
@@ -2844,6 +2839,7 @@ struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *d
        }
        return head;
 }
+EXPORT_SYMBOL_GPL(validate_xmit_skb_list);
 
 static void qdisc_pkt_len_init(struct sk_buff *skb)
 {
@@ -3797,6 +3793,22 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb,
        return skb;
 }
 
+/**
+ *     netdev_is_rx_handler_busy - check if receive handler is registered
+ *     @dev: device to check
+ *
+ *     Check if a receive handler is already registered for a given device.
+ *     Return true if there one.
+ *
+ *     The caller must hold the rtnl_mutex.
+ */
+bool netdev_is_rx_handler_busy(struct net_device *dev)
+{
+       ASSERT_RTNL();
+       return dev && rtnl_dereference(dev->rx_handler);
+}
+EXPORT_SYMBOL_GPL(netdev_is_rx_handler_busy);
+
 /**
  *     netdev_rx_handler_register - register receive handler
  *     @dev: device to register a handler for
@@ -4249,7 +4261,9 @@ static void skb_gro_reset_offset(struct sk_buff *skb)
            pinfo->nr_frags &&
            !PageHighMem(skb_frag_page(frag0))) {
                NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0);
-               NAPI_GRO_CB(skb)->frag0_len = skb_frag_size(frag0);
+               NAPI_GRO_CB(skb)->frag0_len = min_t(unsigned int,
+                                                   skb_frag_size(frag0),
+                                                   skb->end - skb->tail);
        }
 }
 
@@ -4302,7 +4316,8 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
                NAPI_GRO_CB(skb)->same_flow = 0;
                NAPI_GRO_CB(skb)->flush = 0;
                NAPI_GRO_CB(skb)->free = 0;
-               NAPI_GRO_CB(skb)->udp_mark = 0;
+               NAPI_GRO_CB(skb)->encap_mark = 0;
+               NAPI_GRO_CB(skb)->recursion_counter = 0;
                NAPI_GRO_CB(skb)->gro_remcsum_start = 0;
 
                /* Setup for GRO checksum validation */
@@ -4694,6 +4709,7 @@ void __napi_schedule(struct napi_struct *n)
 }
 EXPORT_SYMBOL(__napi_schedule);
 
+#ifndef CONFIG_PREEMPT_RT_FULL
 /**
  * __napi_schedule_irqoff - schedule for receive
  * @n: entry to schedule
@@ -4705,6 +4721,7 @@ void __napi_schedule_irqoff(struct napi_struct *n)
        ____napi_schedule(this_cpu_ptr(&softnet_data), n);
 }
 EXPORT_SYMBOL(__napi_schedule_irqoff);
+#endif
 
 void __napi_complete(struct napi_struct *n)
 {
@@ -4931,13 +4948,21 @@ static void net_rx_action(struct softirq_action *h)
        struct softnet_data *sd = this_cpu_ptr(&softnet_data);
        unsigned long time_limit = jiffies + 2;
        int budget = netdev_budget;
+       struct sk_buff_head tofree_q;
+       struct sk_buff *skb;
        LIST_HEAD(list);
        LIST_HEAD(repoll);
 
+       __skb_queue_head_init(&tofree_q);
+
        local_irq_disable();
+       skb_queue_splice_init(&sd->tofree_queue, &tofree_q);
        list_splice_init(&sd->poll_list, &list);
        local_irq_enable();
 
+       while ((skb = __skb_dequeue(&tofree_q)))
+               kfree_skb(skb);
+
        for (;;) {
                struct napi_struct *n;
 
@@ -5270,6 +5295,7 @@ static inline bool netdev_adjacent_is_neigh_list(struct net_device *dev,
 
 static int __netdev_adjacent_dev_insert(struct net_device *dev,
                                        struct net_device *adj_dev,
+                                       u16 ref_nr,
                                        struct list_head *dev_list,
                                        void *private, bool master)
 {
@@ -5279,7 +5305,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
        adj = __netdev_find_adj(adj_dev, dev_list);
 
        if (adj) {
-               adj->ref_nr++;
+               adj->ref_nr += ref_nr;
                return 0;
        }
 
@@ -5289,7 +5315,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
 
        adj->dev = adj_dev;
        adj->master = master;
-       adj->ref_nr = 1;
+       adj->ref_nr = ref_nr;
        adj->private = private;
        dev_hold(adj_dev);
 
@@ -5328,6 +5354,7 @@ free_adj:
 
 static void __netdev_adjacent_dev_remove(struct net_device *dev,
                                         struct net_device *adj_dev,
+                                        u16 ref_nr,
                                         struct list_head *dev_list)
 {
        struct netdev_adjacent *adj;
@@ -5340,10 +5367,10 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev,
                BUG();
        }
 
-       if (adj->ref_nr > 1) {
-               pr_debug("%s to %s ref_nr-- = %d\n", dev->name, adj_dev->name,
-                        adj->ref_nr-1);
-               adj->ref_nr--;
+       if (adj->ref_nr > ref_nr) {
+               pr_debug("%s to %s ref_nr-%d = %d\n", dev->name, adj_dev->name,
+                        ref_nr, adj->ref_nr-ref_nr);
+               adj->ref_nr -= ref_nr;
                return;
        }
 
@@ -5362,21 +5389,22 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev,
 
 static int __netdev_adjacent_dev_link_lists(struct net_device *dev,
                                            struct net_device *upper_dev,
+                                           u16 ref_nr,
                                            struct list_head *up_list,
                                            struct list_head *down_list,
                                            void *private, bool master)
 {
        int ret;
 
-       ret = __netdev_adjacent_dev_insert(dev, upper_dev, up_list, private,
-                                          master);
+       ret = __netdev_adjacent_dev_insert(dev, upper_dev, ref_nr, up_list,
+                                          private, master);
        if (ret)
                return ret;
 
-       ret = __netdev_adjacent_dev_insert(upper_dev, dev, down_list, private,
-                                          false);
+       ret = __netdev_adjacent_dev_insert(upper_dev, dev, ref_nr, down_list,
+                                          private, false);
        if (ret) {
-               __netdev_adjacent_dev_remove(dev, upper_dev, up_list);
+               __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list);
                return ret;
        }
 
@@ -5384,9 +5412,10 @@ static int __netdev_adjacent_dev_link_lists(struct net_device *dev,
 }
 
 static int __netdev_adjacent_dev_link(struct net_device *dev,
-                                     struct net_device *upper_dev)
+                                     struct net_device *upper_dev,
+                                     u16 ref_nr)
 {
-       return __netdev_adjacent_dev_link_lists(dev, upper_dev,
+       return __netdev_adjacent_dev_link_lists(dev, upper_dev, ref_nr,
                                                &dev->all_adj_list.upper,
                                                &upper_dev->all_adj_list.lower,
                                                NULL, false);
@@ -5394,17 +5423,19 @@ static int __netdev_adjacent_dev_link(struct net_device *dev,
 
 static void __netdev_adjacent_dev_unlink_lists(struct net_device *dev,
                                               struct net_device *upper_dev,
+                                              u16 ref_nr,
                                               struct list_head *up_list,
                                               struct list_head *down_list)
 {
-       __netdev_adjacent_dev_remove(dev, upper_dev, up_list);
-       __netdev_adjacent_dev_remove(upper_dev, dev, down_list);
+       __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list);
+       __netdev_adjacent_dev_remove(upper_dev, dev, ref_nr, down_list);
 }
 
 static void __netdev_adjacent_dev_unlink(struct net_device *dev,
-                                        struct net_device *upper_dev)
+                                        struct net_device *upper_dev,
+                                        u16 ref_nr)
 {
-       __netdev_adjacent_dev_unlink_lists(dev, upper_dev,
+       __netdev_adjacent_dev_unlink_lists(dev, upper_dev, ref_nr,
                                           &dev->all_adj_list.upper,
                                           &upper_dev->all_adj_list.lower);
 }
@@ -5413,17 +5444,17 @@ static int __netdev_adjacent_dev_link_neighbour(struct net_device *dev,
                                                struct net_device *upper_dev,
                                                void *private, bool master)
 {
-       int ret = __netdev_adjacent_dev_link(dev, upper_dev);
+       int ret = __netdev_adjacent_dev_link(dev, upper_dev, 1);
 
        if (ret)
                return ret;
 
-       ret = __netdev_adjacent_dev_link_lists(dev, upper_dev,
+       ret = __netdev_adjacent_dev_link_lists(dev, upper_dev, 1,
                                               &dev->adj_list.upper,
                                               &upper_dev->adj_list.lower,
                                               private, master);
        if (ret) {
-               __netdev_adjacent_dev_unlink(dev, upper_dev);
+               __netdev_adjacent_dev_unlink(dev, upper_dev, 1);
                return ret;
        }
 
@@ -5433,8 +5464,8 @@ static int __netdev_adjacent_dev_link_neighbour(struct net_device *dev,
 static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev,
                                                   struct net_device *upper_dev)
 {
-       __netdev_adjacent_dev_unlink(dev, upper_dev);
-       __netdev_adjacent_dev_unlink_lists(dev, upper_dev,
+       __netdev_adjacent_dev_unlink(dev, upper_dev, 1);
+       __netdev_adjacent_dev_unlink_lists(dev, upper_dev, 1,
                                           &dev->adj_list.upper,
                                           &upper_dev->adj_list.lower);
 }
@@ -5486,7 +5517,7 @@ static int __netdev_upper_dev_link(struct net_device *dev,
                list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) {
                        pr_debug("Interlinking %s with %s, non-neighbour\n",
                                 i->dev->name, j->dev->name);
-                       ret = __netdev_adjacent_dev_link(i->dev, j->dev);
+                       ret = __netdev_adjacent_dev_link(i->dev, j->dev, i->ref_nr);
                        if (ret)
                                goto rollback_mesh;
                }
@@ -5496,7 +5527,7 @@ static int __netdev_upper_dev_link(struct net_device *dev,
        list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) {
                pr_debug("linking %s's upper device %s with %s\n",
                         upper_dev->name, i->dev->name, dev->name);
-               ret = __netdev_adjacent_dev_link(dev, i->dev);
+               ret = __netdev_adjacent_dev_link(dev, i->dev, i->ref_nr);
                if (ret)
                        goto rollback_upper_mesh;
        }
@@ -5505,7 +5536,7 @@ static int __netdev_upper_dev_link(struct net_device *dev,
        list_for_each_entry(i, &dev->all_adj_list.lower, list) {
                pr_debug("linking %s's lower device %s with %s\n", dev->name,
                         i->dev->name, upper_dev->name);
-               ret = __netdev_adjacent_dev_link(i->dev, upper_dev);
+               ret = __netdev_adjacent_dev_link(i->dev, upper_dev, i->ref_nr);
                if (ret)
                        goto rollback_lower_mesh;
        }
@@ -5519,7 +5550,7 @@ rollback_lower_mesh:
        list_for_each_entry(i, &dev->all_adj_list.lower, list) {
                if (i == to_i)
                        break;
-               __netdev_adjacent_dev_unlink(i->dev, upper_dev);
+               __netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr);
        }
 
        i = NULL;
@@ -5529,7 +5560,7 @@ rollback_upper_mesh:
        list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) {
                if (i == to_i)
                        break;
-               __netdev_adjacent_dev_unlink(dev, i->dev);
+               __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr);
        }
 
        i = j = NULL;
@@ -5541,7 +5572,7 @@ rollback_mesh:
                list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) {
                        if (i == to_i && j == to_j)
                                break;
-                       __netdev_adjacent_dev_unlink(i->dev, j->dev);
+                       __netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr);
                }
                if (i == to_i)
                        break;
@@ -5625,16 +5656,16 @@ void netdev_upper_dev_unlink(struct net_device *dev,
         */
        list_for_each_entry(i, &dev->all_adj_list.lower, list)
                list_for_each_entry(j, &upper_dev->all_adj_list.upper, list)
-                       __netdev_adjacent_dev_unlink(i->dev, j->dev);
+                       __netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr);
 
        /* remove also the devices itself from lower/upper device
         * list
         */
        list_for_each_entry(i, &dev->all_adj_list.lower, list)
-               __netdev_adjacent_dev_unlink(i->dev, upper_dev);
+               __netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr);
 
        list_for_each_entry(i, &upper_dev->all_adj_list.upper, list)
-               __netdev_adjacent_dev_unlink(dev, i->dev);
+               __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr);
 
        call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev,
                                      &changeupper_info.info);