Skip to content

Commit

Permalink
net: add CONFIG_PCPU_DEV_REFCNT
Browse files Browse the repository at this point in the history
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.

Signed-off-by: Eric Dumazet <edumazet@google.com>
  • Loading branch information
Eric Dumazet authored and intel-lab-lkp committed Mar 19, 2021
1 parent 38cb576 commit 684c342
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 0 deletions.
13 changes: 13 additions & 0 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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
}

/**
Expand All @@ -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
Expand Down
8 changes: 8 additions & 0 deletions net/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -10740,7 +10746,9 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
return NULL;

free_pcpu:
#ifdef CONFIG_PCPU_DEV_REFCNT
free_percpu(dev->pcpu_refcnt);
#endif
free_dev:
netdev_freemem(dev);
return NULL;
Expand Down Expand Up @@ -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;

Expand Down

0 comments on commit 684c342

Please sign in to comment.