aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2013-10-30 16:10:44 -0400
committerDavid S. Miller <davem@davemloft.net>2013-11-03 23:19:00 -0500
commit74d332c13b2148ae934ea94dac1745ae92efe8e5 (patch)
tree4f8f287774deaba28fa4c85d085d587ae7515aaf
parentb397f99921827e114d7f5600447e172a99c50165 (diff)
net: extend net_device allocation to vmalloc()
Joby Poriyath provided a xen-netback patch to reduce the size of xenvif structure as some netdev allocation could fail under memory pressure/fragmentation. This patch is handling the problem at the core level, allowing any netdev structures to use vmalloc() if kmalloc() failed. 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> Reported-by: Joby Poriyath <joby.poriyath@citrix.com> Cc: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/networking/netdevices.txt10
-rw-r--r--include/linux/netdevice.h1
-rw-r--r--net/core/dev.c22
-rw-r--r--net/core/net-sysfs.c2
4 files changed, 24 insertions, 11 deletions
diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt
index c7ecc7080494..0b1cf6b2a592 100644
--- a/Documentation/networking/netdevices.txt
+++ b/Documentation/networking/netdevices.txt
@@ -10,12 +10,12 @@ network devices.
10struct net_device allocation rules 10struct net_device allocation rules
11================================== 11==================================
12Network device structures need to persist even after module is unloaded and 12Network device structures need to persist even after module is unloaded and
13must be allocated with kmalloc. If device has registered successfully, 13must be allocated with alloc_netdev_mqs() and friends.
14it will be freed on last use by free_netdev. This is required to handle the 14If device has registered successfully, it will be freed on last use
15pathologic case cleanly (example: rmmod mydriver </sys/class/net/myeth/mtu ) 15by free_netdev(). This is required to handle the pathologic case cleanly
16(example: rmmod mydriver </sys/class/net/myeth/mtu )
16 17
17There are routines in net_init.c to handle the common cases of 18alloc_netdev_mqs()/alloc_netdev() reserve extra space for driver
18alloc_etherdev, alloc_netdev. These reserve extra space for driver
19private data which gets freed when the network device is freed. If 19private data which gets freed when the network device is freed. If
20separately allocated data is attached to the network device 20separately allocated data is attached to the network device
21(netdev_priv(dev)) then it is up to the module exit handler to free that. 21(netdev_priv(dev)) then it is up to the module exit handler to free that.
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index cb1d918ecdf1..e6353cafbf05 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1800,6 +1800,7 @@ static inline void unregister_netdevice(struct net_device *dev)
1800 1800
1801int netdev_refcnt_read(const struct net_device *dev); 1801int netdev_refcnt_read(const struct net_device *dev);
1802void free_netdev(struct net_device *dev); 1802void free_netdev(struct net_device *dev);
1803void netdev_freemem(struct net_device *dev);
1803void synchronize_net(void); 1804void synchronize_net(void);
1804int init_dummy_netdev(struct net_device *dev); 1805int init_dummy_netdev(struct net_device *dev);
1805 1806
diff --git a/net/core/dev.c b/net/core/dev.c
index 0054c8c75f50..0e6136546a8c 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6196,6 +6196,16 @@ void netdev_set_default_ethtool_ops(struct net_device *dev,
6196} 6196}
6197EXPORT_SYMBOL_GPL(netdev_set_default_ethtool_ops); 6197EXPORT_SYMBOL_GPL(netdev_set_default_ethtool_ops);
6198 6198
6199void netdev_freemem(struct net_device *dev)
6200{
6201 char *addr = (char *)dev - dev->padded;
6202
6203 if (is_vmalloc_addr(addr))
6204 vfree(addr);
6205 else
6206 kfree(addr);
6207}
6208
6199/** 6209/**
6200 * alloc_netdev_mqs - allocate network device 6210 * alloc_netdev_mqs - allocate network device
6201 * @sizeof_priv: size of private data to allocate space for 6211 * @sizeof_priv: size of private data to allocate space for
@@ -6239,7 +6249,9 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
6239 /* ensure 32-byte alignment of whole construct */ 6249 /* ensure 32-byte alignment of whole construct */
6240 alloc_size += NETDEV_ALIGN - 1; 6250 alloc_size += NETDEV_ALIGN - 1;
6241 6251
6242 p = kzalloc(alloc_size, GFP_KERNEL); 6252 p = kzalloc(alloc_size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
6253 if (!p)
6254 p = vzalloc(alloc_size);
6243 if (!p) 6255 if (!p)
6244 return NULL; 6256 return NULL;
6245 6257
@@ -6248,7 +6260,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
6248 6260
6249 dev->pcpu_refcnt = alloc_percpu(int); 6261 dev->pcpu_refcnt = alloc_percpu(int);
6250 if (!dev->pcpu_refcnt) 6262 if (!dev->pcpu_refcnt)
6251 goto free_p; 6263 goto free_dev;
6252 6264
6253 if (dev_addr_init(dev)) 6265 if (dev_addr_init(dev))
6254 goto free_pcpu; 6266 goto free_pcpu;
@@ -6301,8 +6313,8 @@ free_pcpu:
6301 kfree(dev->_rx); 6313 kfree(dev->_rx);
6302#endif 6314#endif
6303 6315
6304free_p: 6316free_dev:
6305 kfree(p); 6317 netdev_freemem(dev);
6306 return NULL; 6318 return NULL;
6307} 6319}
6308EXPORT_SYMBOL(alloc_netdev_mqs); 6320EXPORT_SYMBOL(alloc_netdev_mqs);
@@ -6339,7 +6351,7 @@ void free_netdev(struct net_device *dev)
6339 6351
6340 /* Compatibility with error handling in drivers */ 6352 /* Compatibility with error handling in drivers */
6341 if (dev->reg_state == NETREG_UNINITIALIZED) { 6353 if (dev->reg_state == NETREG_UNINITIALIZED) {
6342 kfree((char *)dev - dev->padded); 6354 netdev_freemem(dev);
6343 return; 6355 return;
6344 } 6356 }
6345 6357
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index d954b56b4e47..d03f2c9750fa 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -1263,7 +1263,7 @@ static void netdev_release(struct device *d)
1263 BUG_ON(dev->reg_state != NETREG_RELEASED); 1263 BUG_ON(dev->reg_state != NETREG_RELEASED);
1264 1264
1265 kfree(dev->ifalias); 1265 kfree(dev->ifalias);
1266 kfree((char *)dev - dev->padded); 1266 netdev_freemem(dev);
1267} 1267}
1268 1268
1269static const void *net_namespace(struct device *d) 1269static const void *net_namespace(struct device *d)