diff options
author | Eric Dumazet <edumazet@google.com> | 2013-06-20 04:15:51 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-06-24 02:56:55 -0400 |
commit | 60877a32bce00041528576e6b8df5abe9251fa73 (patch) | |
tree | c949fd23e9a57d33a1597db4ad100ac2227fa19b /net/core | |
parent | b0b02c77d7aa9ebeea5d4ea7e4f3fd745ad7f81c (diff) |
net: allow large number of tx queues
netif_alloc_netdev_queues() uses kcalloc() to allocate memory
for the "struct netdev_queue *_tx" array.
For large number of tx queues, kcalloc() might fail, so this
patch does a fallback to vzalloc().
As vmalloc() adds overhead on a critical network path, add __GFP_REPEAT
to kzalloc() flags to do this fallback only when really needed.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/dev.c | 26 |
1 files changed, 19 insertions, 7 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index fa007dba6beb..722f633926e0 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -130,6 +130,7 @@ | |||
130 | #include <linux/cpu_rmap.h> | 130 | #include <linux/cpu_rmap.h> |
131 | #include <linux/static_key.h> | 131 | #include <linux/static_key.h> |
132 | #include <linux/hashtable.h> | 132 | #include <linux/hashtable.h> |
133 | #include <linux/vmalloc.h> | ||
133 | 134 | ||
134 | #include "net-sysfs.h" | 135 | #include "net-sysfs.h" |
135 | 136 | ||
@@ -5253,17 +5254,28 @@ static void netdev_init_one_queue(struct net_device *dev, | |||
5253 | #endif | 5254 | #endif |
5254 | } | 5255 | } |
5255 | 5256 | ||
5257 | static void netif_free_tx_queues(struct net_device *dev) | ||
5258 | { | ||
5259 | if (is_vmalloc_addr(dev->_tx)) | ||
5260 | vfree(dev->_tx); | ||
5261 | else | ||
5262 | kfree(dev->_tx); | ||
5263 | } | ||
5264 | |||
5256 | static int netif_alloc_netdev_queues(struct net_device *dev) | 5265 | static int netif_alloc_netdev_queues(struct net_device *dev) |
5257 | { | 5266 | { |
5258 | unsigned int count = dev->num_tx_queues; | 5267 | unsigned int count = dev->num_tx_queues; |
5259 | struct netdev_queue *tx; | 5268 | struct netdev_queue *tx; |
5269 | size_t sz = count * sizeof(*tx); | ||
5260 | 5270 | ||
5261 | BUG_ON(count < 1); | 5271 | BUG_ON(count < 1 || count > 0xffff); |
5262 | |||
5263 | tx = kcalloc(count, sizeof(struct netdev_queue), GFP_KERNEL); | ||
5264 | if (!tx) | ||
5265 | return -ENOMEM; | ||
5266 | 5272 | ||
5273 | tx = kzalloc(sz, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT); | ||
5274 | if (!tx) { | ||
5275 | tx = vzalloc(sz); | ||
5276 | if (!tx) | ||
5277 | return -ENOMEM; | ||
5278 | } | ||
5267 | dev->_tx = tx; | 5279 | dev->_tx = tx; |
5268 | 5280 | ||
5269 | netdev_for_each_tx_queue(dev, netdev_init_one_queue, NULL); | 5281 | netdev_for_each_tx_queue(dev, netdev_init_one_queue, NULL); |
@@ -5811,7 +5823,7 @@ free_all: | |||
5811 | 5823 | ||
5812 | free_pcpu: | 5824 | free_pcpu: |
5813 | free_percpu(dev->pcpu_refcnt); | 5825 | free_percpu(dev->pcpu_refcnt); |
5814 | kfree(dev->_tx); | 5826 | netif_free_tx_queues(dev); |
5815 | #ifdef CONFIG_RPS | 5827 | #ifdef CONFIG_RPS |
5816 | kfree(dev->_rx); | 5828 | kfree(dev->_rx); |
5817 | #endif | 5829 | #endif |
@@ -5836,7 +5848,7 @@ void free_netdev(struct net_device *dev) | |||
5836 | 5848 | ||
5837 | release_net(dev_net(dev)); | 5849 | release_net(dev_net(dev)); |
5838 | 5850 | ||
5839 | kfree(dev->_tx); | 5851 | netif_free_tx_queues(dev); |
5840 | #ifdef CONFIG_RPS | 5852 | #ifdef CONFIG_RPS |
5841 | kfree(dev->_rx); | 5853 | kfree(dev->_rx); |
5842 | #endif | 5854 | #endif |