Skip to content

Commit 74d332c

Browse files
edumazetdavem330
authored andcommitted
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>
1 parent b397f99 commit 74d332c

File tree

4 files changed

+24
-11
lines changed

4 files changed

+24
-11
lines changed

Documentation/networking/netdevices.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ network devices.
1010
struct net_device allocation rules
1111
==================================
1212
Network device structures need to persist even after module is unloaded and
13-
must be allocated with kmalloc. If device has registered successfully,
14-
it will be freed on last use by free_netdev. This is required to handle the
15-
pathologic case cleanly (example: rmmod mydriver </sys/class/net/myeth/mtu )
13+
must be allocated with alloc_netdev_mqs() and friends.
14+
If device has registered successfully, it will be freed on last use
15+
by free_netdev(). This is required to handle the pathologic case cleanly
16+
(example: rmmod mydriver </sys/class/net/myeth/mtu )
1617

17-
There are routines in net_init.c to handle the common cases of
18-
alloc_etherdev, alloc_netdev. These reserve extra space for driver
18+
alloc_netdev_mqs()/alloc_netdev() reserve extra space for driver
1919
private data which gets freed when the network device is freed. If
2020
separately allocated data is attached to the network device
2121
(netdev_priv(dev)) then it is up to the module exit handler to free that.

include/linux/netdevice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1800,6 +1800,7 @@ static inline void unregister_netdevice(struct net_device *dev)
18001800

18011801
int netdev_refcnt_read(const struct net_device *dev);
18021802
void free_netdev(struct net_device *dev);
1803+
void netdev_freemem(struct net_device *dev);
18031804
void synchronize_net(void);
18041805
int init_dummy_netdev(struct net_device *dev);
18051806

net/core/dev.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6196,6 +6196,16 @@ void netdev_set_default_ethtool_ops(struct net_device *dev,
61966196
}
61976197
EXPORT_SYMBOL_GPL(netdev_set_default_ethtool_ops);
61986198

6199+
void 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+
61996209
/**
62006210
* alloc_netdev_mqs - allocate network device
62016211
* @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,
62396249
/* ensure 32-byte alignment of whole construct */
62406250
alloc_size += NETDEV_ALIGN - 1;
62416251

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);
62436255
if (!p)
62446256
return NULL;
62456257

@@ -6248,7 +6260,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
62486260

62496261
dev->pcpu_refcnt = alloc_percpu(int);
62506262
if (!dev->pcpu_refcnt)
6251-
goto free_p;
6263+
goto free_dev;
62526264

62536265
if (dev_addr_init(dev))
62546266
goto free_pcpu;
@@ -6301,8 +6313,8 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
63016313
kfree(dev->_rx);
63026314
#endif
63036315

6304-
free_p:
6305-
kfree(p);
6316+
free_dev:
6317+
netdev_freemem(dev);
63066318
return NULL;
63076319
}
63086320
EXPORT_SYMBOL(alloc_netdev_mqs);
@@ -6339,7 +6351,7 @@ void free_netdev(struct net_device *dev)
63396351

63406352
/* Compatibility with error handling in drivers */
63416353
if (dev->reg_state == NETREG_UNINITIALIZED) {
6342-
kfree((char *)dev - dev->padded);
6354+
netdev_freemem(dev);
63436355
return;
63446356
}
63456357

net/core/net-sysfs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1263,7 +1263,7 @@ static void netdev_release(struct device *d)
12631263
BUG_ON(dev->reg_state != NETREG_RELEASED);
12641264

12651265
kfree(dev->ifalias);
1266-
kfree((char *)dev - dev->padded);
1266+
netdev_freemem(dev);
12671267
}
12681268

12691269
static const void *net_namespace(struct device *d)

0 commit comments

Comments
 (0)