Skip to content

Commit 13cabc4

Browse files
alobakinkuba-moo
authored andcommitted
netdevice: define and allocate &net_device _properly_
In fact, this structure contains a flexible array at the end, but historically its size, alignment etc., is calculated manually. There are several instances of the structure embedded into other structures, but also there's ongoing effort to remove them and we could in the meantime declare &net_device properly. Declare the array explicitly, use struct_size() and store the array size inside the structure, so that __counted_by() can be applied. Don't use PTR_ALIGN(), as SLUB itself tries its best to ensure the allocated buffer is aligned to what the user expects. Also, change its alignment from %NETDEV_ALIGN to the cacheline size as per several suggestions on the netdev ML. bloat-o-meter for vmlinux: free_netdev 445 440 -5 netdev_freemem 24 - -24 alloc_netdev_mqs 1481 1450 -31 On x86_64 with several NICs of different vendors, I was never able to get a &net_device pointer not aligned to the cacheline size after the change. Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com> Signed-off-by: Breno Leitao <leitao@debian.org> Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Kees Cook <kees@kernel.org> Link: https://patch.msgid.link/20240710113036.2125584-1-leitao@debian.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 8341eee commit 13cabc4

File tree

3 files changed

+16
-31
lines changed

3 files changed

+16
-31
lines changed

include/linux/netdevice.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1819,7 +1819,8 @@ enum netdev_reg_state {
18191819
* @priv_flags: Like 'flags' but invisible to userspace,
18201820
* see if.h for the definitions
18211821
* @gflags: Global flags ( kept as legacy )
1822-
* @padded: How much padding added by alloc_netdev()
1822+
* @priv_len: Size of the ->priv flexible array
1823+
* @priv: Flexible array containing private data
18231824
* @operstate: RFC2863 operstate
18241825
* @link_mode: Mapping policy to operstate
18251826
* @if_port: Selectable AUI, TP, ...
@@ -2199,10 +2200,10 @@ struct net_device {
21992200
unsigned short neigh_priv_len;
22002201
unsigned short dev_id;
22012202
unsigned short dev_port;
2202-
unsigned short padded;
2203+
int irq;
2204+
u32 priv_len;
22032205

22042206
spinlock_t addr_list_lock;
2205-
int irq;
22062207

22072208
struct netdev_hw_addr_list uc;
22082209
struct netdev_hw_addr_list mc;
@@ -2406,7 +2407,10 @@ struct net_device {
24062407

24072408
/** @irq_moder: dim parameters used if IS_ENABLED(CONFIG_DIMLIB). */
24082409
struct dim_irq_moder *irq_moder;
2409-
};
2410+
2411+
u8 priv[] ____cacheline_aligned
2412+
__counted_by(priv_len);
2413+
} ____cacheline_aligned;
24102414
#define to_net_dev(d) container_of(d, struct net_device, dev)
24112415

24122416
/*
@@ -2596,7 +2600,7 @@ void dev_net_set(struct net_device *dev, struct net *net)
25962600
*/
25972601
static inline void *netdev_priv(const struct net_device *dev)
25982602
{
2599-
return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);
2603+
return (void *)dev->priv;
26002604
}
26012605

26022606
/* Set the sysfs physical device reference for the network logical device
@@ -3127,7 +3131,6 @@ static inline void unregister_netdevice(struct net_device *dev)
31273131

31283132
int netdev_refcnt_read(const struct net_device *dev);
31293133
void free_netdev(struct net_device *dev);
3130-
void netdev_freemem(struct net_device *dev);
31313134
void init_dummy_netdev(struct net_device *dev);
31323135

31333136
struct net_device *netdev_get_xmit_slave(struct net_device *dev,

net/core/dev.c

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11006,13 +11006,6 @@ void netdev_sw_irq_coalesce_default_on(struct net_device *dev)
1100611006
}
1100711007
EXPORT_SYMBOL_GPL(netdev_sw_irq_coalesce_default_on);
1100811008

11009-
void netdev_freemem(struct net_device *dev)
11010-
{
11011-
char *addr = (char *)dev - dev->padded;
11012-
11013-
kvfree(addr);
11014-
}
11015-
1101611009
/**
1101711010
* alloc_netdev_mqs - allocate network device
1101811011
* @sizeof_priv: size of private data to allocate space for
@@ -11032,8 +11025,6 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
1103211025
unsigned int txqs, unsigned int rxqs)
1103311026
{
1103411027
struct net_device *dev;
11035-
unsigned int alloc_size;
11036-
struct net_device *p;
1103711028

1103811029
BUG_ON(strlen(name) >= sizeof(dev->name));
1103911030

@@ -11047,21 +11038,12 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
1104711038
return NULL;
1104811039
}
1104911040

11050-
alloc_size = sizeof(struct net_device);
11051-
if (sizeof_priv) {
11052-
/* ensure 32-byte alignment of private area */
11053-
alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);
11054-
alloc_size += sizeof_priv;
11055-
}
11056-
/* ensure 32-byte alignment of whole construct */
11057-
alloc_size += NETDEV_ALIGN - 1;
11058-
11059-
p = kvzalloc(alloc_size, GFP_KERNEL_ACCOUNT | __GFP_RETRY_MAYFAIL);
11060-
if (!p)
11041+
dev = kvzalloc(struct_size(dev, priv, sizeof_priv),
11042+
GFP_KERNEL_ACCOUNT | __GFP_RETRY_MAYFAIL);
11043+
if (!dev)
1106111044
return NULL;
1106211045

11063-
dev = PTR_ALIGN(p, NETDEV_ALIGN);
11064-
dev->padded = (char *)dev - (char *)p;
11046+
dev->priv_len = sizeof_priv;
1106511047

1106611048
ref_tracker_dir_init(&dev->refcnt_tracker, 128, name);
1106711049
#ifdef CONFIG_PCPU_DEV_REFCNT
@@ -11148,7 +11130,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
1114811130
free_percpu(dev->pcpu_refcnt);
1114911131
free_dev:
1115011132
#endif
11151-
netdev_freemem(dev);
11133+
kvfree(dev);
1115211134
return NULL;
1115311135
}
1115411136
EXPORT_SYMBOL(alloc_netdev_mqs);
@@ -11203,7 +11185,7 @@ void free_netdev(struct net_device *dev)
1120311185
/* Compatibility with error handling in drivers */
1120411186
if (dev->reg_state == NETREG_UNINITIALIZED ||
1120511187
dev->reg_state == NETREG_DUMMY) {
11206-
netdev_freemem(dev);
11188+
kvfree(dev);
1120711189
return;
1120811190
}
1120911191

net/core/net-sysfs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2028,7 +2028,7 @@ static void netdev_release(struct device *d)
20282028
* device is dead and about to be freed.
20292029
*/
20302030
kfree(rcu_access_pointer(dev->ifalias));
2031-
netdev_freemem(dev);
2031+
kvfree(dev);
20322032
}
20332033

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

0 commit comments

Comments
 (0)