mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
net: add CONFIG_PCPU_DEV_REFCNT
I was working on a syzbot issue, claiming one device could not be dismantled because its refcount was -1 unregister_netdevice: waiting for sit0 to become free. Usage count = -1 It would be nice if syzbot could trigger a warning at the time this reference count became negative. This patch adds CONFIG_PCPU_DEV_REFCNT options which defaults to per cpu variables (as before this patch) on SMP builds. v2: free_dev label in alloc_netdev_mqs() is moved to avoid a compiler warning (-Wunused-label), as reported by kernel test robot <lkp@intel.com> Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
942f0c6e28
commit
919067cc84
@ -2092,7 +2092,12 @@ struct net_device {
|
||||
u32 proto_down_reason;
|
||||
|
||||
struct list_head todo_list;
|
||||
|
||||
#ifdef CONFIG_PCPU_DEV_REFCNT
|
||||
int __percpu *pcpu_refcnt;
|
||||
#else
|
||||
refcount_t dev_refcnt;
|
||||
#endif
|
||||
|
||||
struct list_head link_watch_list;
|
||||
|
||||
@ -4044,7 +4049,11 @@ void netdev_run_todo(void);
|
||||
*/
|
||||
static inline void dev_put(struct net_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_PCPU_DEV_REFCNT
|
||||
this_cpu_dec(*dev->pcpu_refcnt);
|
||||
#else
|
||||
refcount_dec(&dev->dev_refcnt);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4055,7 +4064,11 @@ static inline void dev_put(struct net_device *dev)
|
||||
*/
|
||||
static inline void dev_hold(struct net_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_PCPU_DEV_REFCNT
|
||||
this_cpu_inc(*dev->pcpu_refcnt);
|
||||
#else
|
||||
refcount_inc(&dev->dev_refcnt);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Carrier loss detection, dial on demand. The functions netif_carrier_on
|
||||
|
@ -245,6 +245,14 @@ source "net/l3mdev/Kconfig"
|
||||
source "net/qrtr/Kconfig"
|
||||
source "net/ncsi/Kconfig"
|
||||
|
||||
config PCPU_DEV_REFCNT
|
||||
bool "Use percpu variables to maintain network device refcount"
|
||||
depends on SMP
|
||||
default y
|
||||
help
|
||||
network device refcount are using per cpu variables if this option is set.
|
||||
This can be forced to N to detect underflows (with a performance drop).
|
||||
|
||||
config RPS
|
||||
bool
|
||||
depends on SMP && SYSFS
|
||||
|
@ -10312,11 +10312,15 @@ EXPORT_SYMBOL(register_netdev);
|
||||
|
||||
int netdev_refcnt_read(const struct net_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_PCPU_DEV_REFCNT
|
||||
int i, refcnt = 0;
|
||||
|
||||
for_each_possible_cpu(i)
|
||||
refcnt += *per_cpu_ptr(dev->pcpu_refcnt, i);
|
||||
return refcnt;
|
||||
#else
|
||||
return refcount_read(&dev->dev_refcnt);
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_refcnt_read);
|
||||
|
||||
@ -10674,9 +10678,11 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
|
||||
dev = PTR_ALIGN(p, NETDEV_ALIGN);
|
||||
dev->padded = (char *)dev - (char *)p;
|
||||
|
||||
#ifdef CONFIG_PCPU_DEV_REFCNT
|
||||
dev->pcpu_refcnt = alloc_percpu(int);
|
||||
if (!dev->pcpu_refcnt)
|
||||
goto free_dev;
|
||||
#endif
|
||||
|
||||
if (dev_addr_init(dev))
|
||||
goto free_pcpu;
|
||||
@ -10740,8 +10746,10 @@ free_all:
|
||||
return NULL;
|
||||
|
||||
free_pcpu:
|
||||
#ifdef CONFIG_PCPU_DEV_REFCNT
|
||||
free_percpu(dev->pcpu_refcnt);
|
||||
free_dev:
|
||||
#endif
|
||||
netdev_freemem(dev);
|
||||
return NULL;
|
||||
}
|
||||
@ -10783,8 +10791,10 @@ void free_netdev(struct net_device *dev)
|
||||
list_for_each_entry_safe(p, n, &dev->napi_list, dev_list)
|
||||
netif_napi_del(p);
|
||||
|
||||
#ifdef CONFIG_PCPU_DEV_REFCNT
|
||||
free_percpu(dev->pcpu_refcnt);
|
||||
dev->pcpu_refcnt = NULL;
|
||||
#endif
|
||||
free_percpu(dev->xdp_bulkq);
|
||||
dev->xdp_bulkq = NULL;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user