]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/core/dev.c
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[net-next-2.6.git] / net / core / dev.c
index 63bd20a75929d798a8c3689520ab9a0b811a31bc..42b200fdf12e42042fa30a45eec6ab33bc2bef8e 100644 (file)
 #include <linux/random.h>
 #include <trace/events/napi.h>
 #include <linux/pci.h>
+#include <linux/inetdevice.h>
 
 #include "net-sysfs.h"
 
@@ -371,6 +372,14 @@ static inline void netdev_set_addr_lockdep_class(struct net_device *dev)
  *                                                     --ANK (980803)
  */
 
+static inline struct list_head *ptype_head(const struct packet_type *pt)
+{
+       if (pt->type == htons(ETH_P_ALL))
+               return &ptype_all;
+       else
+               return &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK];
+}
+
 /**
  *     dev_add_pack - add packet handler
  *     @pt: packet type declaration
@@ -386,16 +395,11 @@ static inline void netdev_set_addr_lockdep_class(struct net_device *dev)
 
 void dev_add_pack(struct packet_type *pt)
 {
-       int hash;
+       struct list_head *head = ptype_head(pt);
 
-       spin_lock_bh(&ptype_lock);
-       if (pt->type == htons(ETH_P_ALL))
-               list_add_rcu(&pt->list, &ptype_all);
-       else {
-               hash = ntohs(pt->type) & PTYPE_HASH_MASK;
-               list_add_rcu(&pt->list, &ptype_base[hash]);
-       }
-       spin_unlock_bh(&ptype_lock);
+       spin_lock(&ptype_lock);
+       list_add_rcu(&pt->list, head);
+       spin_unlock(&ptype_lock);
 }
 EXPORT_SYMBOL(dev_add_pack);
 
@@ -414,15 +418,10 @@ EXPORT_SYMBOL(dev_add_pack);
  */
 void __dev_remove_pack(struct packet_type *pt)
 {
-       struct list_head *head;
+       struct list_head *head = ptype_head(pt);
        struct packet_type *pt1;
 
-       spin_lock_bh(&ptype_lock);
-
-       if (pt->type == htons(ETH_P_ALL))
-               head = &ptype_all;
-       else
-               head = &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK];
+       spin_lock(&ptype_lock);
 
        list_for_each_entry(pt1, head, list) {
                if (pt == pt1) {
@@ -433,7 +432,7 @@ void __dev_remove_pack(struct packet_type *pt)
 
        printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt);
 out:
-       spin_unlock_bh(&ptype_lock);
+       spin_unlock(&ptype_lock);
 }
 EXPORT_SYMBOL(__dev_remove_pack);
 
@@ -2058,16 +2057,16 @@ static struct netdev_queue *dev_pick_tx(struct net_device *dev,
                                        struct sk_buff *skb)
 {
        int queue_index;
-       struct sock *sk = skb->sk;
+       const struct net_device_ops *ops = dev->netdev_ops;
 
-       queue_index = sk_tx_queue_get(sk);
-       if (queue_index < 0) {
-               const struct net_device_ops *ops = dev->netdev_ops;
+       if (ops->ndo_select_queue) {
+               queue_index = ops->ndo_select_queue(dev, skb);
+               queue_index = dev_cap_txqueue(dev, queue_index);
+       } else {
+               struct sock *sk = skb->sk;
+               queue_index = sk_tx_queue_get(sk);
+               if (queue_index < 0) {
 
-               if (ops->ndo_select_queue) {
-                       queue_index = ops->ndo_select_queue(dev, skb);
-                       queue_index = dev_cap_txqueue(dev, queue_index);
-               } else {
                        queue_index = 0;
                        if (dev->real_num_tx_queues > 1)
                                queue_index = skb_tx_hash(dev, skb);
@@ -2345,7 +2344,7 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
                       struct rps_dev_flow **rflowp)
 {
        struct netdev_rx_queue *rxqueue;
-       struct rps_map *map;
+       struct rps_map *map = NULL;
        struct rps_dev_flow_table *flow_table;
        struct rps_sock_flow_table *sock_flow_table;
        int cpu = -1;
@@ -2363,8 +2362,17 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
        } else
                rxqueue = dev->_rx;
 
-       if (!rxqueue->rps_map && !rxqueue->rps_flow_table)
+       if (rxqueue->rps_map) {
+               map = rcu_dereference(rxqueue->rps_map);
+               if (map && map->len == 1) {
+                       tcpu = map->cpus[0];
+                       if (cpu_online(tcpu))
+                               cpu = tcpu;
+                       goto done;
+               }
+       } else if (!rxqueue->rps_flow_table) {
                goto done;
+       }
 
        skb_reset_network_header(skb);
        if (!skb_get_rxhash(skb))
@@ -2409,7 +2417,6 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
                }
        }
 
-       map = rcu_dereference(rxqueue->rps_map);
        if (map) {
                tcpu = map->cpus[((u64) skb->rxhash * map->len) >> 32];
 
@@ -3063,7 +3070,7 @@ out:
        return netif_receive_skb(skb);
 }
 
-static void napi_gro_flush(struct napi_struct *napi)
+inline void napi_gro_flush(struct napi_struct *napi)
 {
        struct sk_buff *skb, *next;
 
@@ -3076,6 +3083,7 @@ static void napi_gro_flush(struct napi_struct *napi)
        napi->gro_count = 0;
        napi->gro_list = NULL;
 }
+EXPORT_SYMBOL(napi_gro_flush);
 
 enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
 {
@@ -4860,7 +4868,7 @@ static void rollback_registered_many(struct list_head *head)
        dev = list_first_entry(head, struct net_device, unreg_list);
        call_netdevice_notifiers(NETDEV_UNREGISTER_BATCH, dev);
 
-       synchronize_net();
+       rcu_barrier();
 
        list_for_each_entry(dev, head, unreg_list)
                dev_put(dev);
@@ -4956,6 +4964,34 @@ void netif_stacked_transfer_operstate(const struct net_device *rootdev,
 }
 EXPORT_SYMBOL(netif_stacked_transfer_operstate);
 
+static int netif_alloc_rx_queues(struct net_device *dev)
+{
+#ifdef CONFIG_RPS
+       unsigned int i, count = dev->num_rx_queues;
+
+       if (count) {
+               struct netdev_rx_queue *rx;
+
+               rx = kcalloc(count, sizeof(struct netdev_rx_queue), GFP_KERNEL);
+               if (!rx) {
+                       pr_err("netdev: Unable to allocate %u rx queues.\n",
+                              count);
+                       return -ENOMEM;
+               }
+               dev->_rx = rx;
+               atomic_set(&rx->count, count);
+
+               /*
+                * Set a pointer to first element in the array which holds the
+                * reference count.
+                */
+               for (i = 0; i < count; i++)
+                       rx[i].first = rx;
+       }
+#endif
+       return 0;
+}
+
 /**
  *     register_netdevice      - register a network device
  *     @dev: device to register
@@ -4993,24 +5029,10 @@ int register_netdevice(struct net_device *dev)
 
        dev->iflink = -1;
 
-#ifdef CONFIG_RPS
-       if (!dev->num_rx_queues) {
-               /*
-                * Allocate a single RX queue if driver never called
-                * alloc_netdev_mq
-                */
-
-               dev->_rx = kzalloc(sizeof(struct netdev_rx_queue), GFP_KERNEL);
-               if (!dev->_rx) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
+       ret = netif_alloc_rx_queues(dev);
+       if (ret)
+               goto out;
 
-               dev->_rx->first = dev->_rx;
-               atomic_set(&dev->_rx->count, 1);
-               dev->num_rx_queues = 1;
-       }
-#endif
        /* Init, if this function is available */
        if (dev->netdev_ops->ndo_init) {
                ret = dev->netdev_ops->ndo_init(dev);
@@ -5050,6 +5072,12 @@ int register_netdevice(struct net_device *dev)
        if (dev->features & NETIF_F_SG)
                dev->features |= NETIF_F_GSO;
 
+       /* Enable GRO and NETIF_F_HIGHDMA for vlans by default,
+        * vlan_dev_init() will do the dev->features check, so these features
+        * are enabled only if supported by underlying device.
+        */
+       dev->vlan_features |= (NETIF_F_GRO | NETIF_F_HIGHDMA);
+
        ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev);
        ret = notifier_to_errno(ret);
        if (ret)
@@ -5279,7 +5307,7 @@ void netdev_run_todo(void)
 
                /* paranoia */
                BUG_ON(atomic_read(&dev->refcnt));
-               WARN_ON(dev->ip_ptr);
+               WARN_ON(rcu_dereference_raw(dev->ip_ptr));
                WARN_ON(dev->ip6_ptr);
                WARN_ON(dev->dn_ptr);
 
@@ -5401,10 +5429,6 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
        struct net_device *dev;
        size_t alloc_size;
        struct net_device *p;
-#ifdef CONFIG_RPS
-       struct netdev_rx_queue *rx;
-       int i;
-#endif
 
        BUG_ON(strlen(name) >= sizeof(dev->name));
 
@@ -5430,29 +5454,12 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
                goto free_p;
        }
 
-#ifdef CONFIG_RPS
-       rx = kcalloc(queue_count, sizeof(struct netdev_rx_queue), GFP_KERNEL);
-       if (!rx) {
-               printk(KERN_ERR "alloc_netdev: Unable to allocate "
-                      "rx queues.\n");
-               goto free_tx;
-       }
-
-       atomic_set(&rx->count, queue_count);
-
-       /*
-        * Set a pointer to first element in the array which holds the
-        * reference count.
-        */
-       for (i = 0; i < queue_count; i++)
-               rx[i].first = rx;
-#endif
 
        dev = PTR_ALIGN(p, NETDEV_ALIGN);
        dev->padded = (char *)dev - (char *)p;
 
        if (dev_addr_init(dev))
-               goto free_rx;
+               goto free_tx;
 
        dev_mc_init(dev);
        dev_uc_init(dev);
@@ -5464,7 +5471,6 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
        dev->real_num_tx_queues = queue_count;
 
 #ifdef CONFIG_RPS
-       dev->_rx = rx;
        dev->num_rx_queues = queue_count;
 #endif
 
@@ -5482,11 +5488,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
        strcpy(dev->name, name);
        return dev;
 
-free_rx:
-#ifdef CONFIG_RPS
-       kfree(rx);
 free_tx:
-#endif
        kfree(tx);
 free_p:
        kfree(p);
@@ -5673,6 +5675,10 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
 
        /* Notify protocols, that we are about to destroy
           this device. They should clean all the things.
+
+          Note that dev->reg_state stays at NETREG_REGISTERED.
+          This is wanted because this way 8021q and macvlan know
+          the device is just moving and can keep their slaves up.
        */
        call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
        call_netdevice_notifiers(NETDEV_UNREGISTER_BATCH, dev);