aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-02-08 18:02:50 -0500
committerDavid S. Miller <davem@davemloft.net>2011-02-08 18:02:50 -0500
commit8d3bdbd55a7e2a3f2c148a4830aa26dd682b21c4 (patch)
treed32637a46d04190f1123c2e7ad1ba460f53b8ff9 /net
parentb2df5a8446e135f7648736b8bec8179c88ce360d (diff)
net: Fix lockdep regression caused by initializing netdev queues too early.
In commit aa9421041128abb4d269ee1dc502ff65fb3b7d69 ("net: init ingress queue") we moved the allocation and lock initialization of the queues into alloc_netdev_mq() since register_netdevice() is way too late. The problem is that dev->type is not setup until the setup() callback is invoked by alloc_netdev_mq(), and the dev->type is what determines the lockdep class to use for the locks in the queues. Fix this by doing the queue allocation after the setup() callback runs. This is safe because the setup() callback is not allowed to make any state changes that need to be undone on error (memory allocations, etc.). It may, however, make state changes that are undone by free_netdev() (such as netif_napi_add(), which is done by the ipoib driver's setup routine). The previous code also leaked a reference to the &init_net namespace object on RX/TX queue allocation failures. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/dev.c27
1 files changed, 16 insertions, 11 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index b6d0bf875a8e..8e726cb47ed7 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5660,30 +5660,35 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
5660 5660
5661 dev_net_set(dev, &init_net); 5661 dev_net_set(dev, &init_net);
5662 5662
5663 dev->gso_max_size = GSO_MAX_SIZE;
5664
5665 INIT_LIST_HEAD(&dev->ethtool_ntuple_list.list);
5666 dev->ethtool_ntuple_list.count = 0;
5667 INIT_LIST_HEAD(&dev->napi_list);
5668 INIT_LIST_HEAD(&dev->unreg_list);
5669 INIT_LIST_HEAD(&dev->link_watch_list);
5670 dev->priv_flags = IFF_XMIT_DST_RELEASE;
5671 setup(dev);
5672
5663 dev->num_tx_queues = txqs; 5673 dev->num_tx_queues = txqs;
5664 dev->real_num_tx_queues = txqs; 5674 dev->real_num_tx_queues = txqs;
5665 if (netif_alloc_netdev_queues(dev)) 5675 if (netif_alloc_netdev_queues(dev))
5666 goto free_pcpu; 5676 goto free_all;
5667 5677
5668#ifdef CONFIG_RPS 5678#ifdef CONFIG_RPS
5669 dev->num_rx_queues = rxqs; 5679 dev->num_rx_queues = rxqs;
5670 dev->real_num_rx_queues = rxqs; 5680 dev->real_num_rx_queues = rxqs;
5671 if (netif_alloc_rx_queues(dev)) 5681 if (netif_alloc_rx_queues(dev))
5672 goto free_pcpu; 5682 goto free_all;
5673#endif 5683#endif
5674 5684
5675 dev->gso_max_size = GSO_MAX_SIZE;
5676
5677 INIT_LIST_HEAD(&dev->ethtool_ntuple_list.list);
5678 dev->ethtool_ntuple_list.count = 0;
5679 INIT_LIST_HEAD(&dev->napi_list);
5680 INIT_LIST_HEAD(&dev->unreg_list);
5681 INIT_LIST_HEAD(&dev->link_watch_list);
5682 dev->priv_flags = IFF_XMIT_DST_RELEASE;
5683 setup(dev);
5684 strcpy(dev->name, name); 5685 strcpy(dev->name, name);
5685 return dev; 5686 return dev;
5686 5687
5688free_all:
5689 free_netdev(dev);
5690 return NULL;
5691
5687free_pcpu: 5692free_pcpu:
5688 free_percpu(dev->pcpu_refcnt); 5693 free_percpu(dev->pcpu_refcnt);
5689 kfree(dev->_tx); 5694 kfree(dev->_tx);