aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2013-06-20 04:15:51 -0400
committerDavid S. Miller <davem@davemloft.net>2013-06-24 02:56:55 -0400
commit60877a32bce00041528576e6b8df5abe9251fa73 (patch)
treec949fd23e9a57d33a1597db4ad100ac2227fa19b /net/core
parentb0b02c77d7aa9ebeea5d4ea7e4f3fd745ad7f81c (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.c26
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
5257static 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
5256static int netif_alloc_netdev_queues(struct net_device *dev) 5265static 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
5812free_pcpu: 5824free_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