net: add net device refcount tracker infrastructure
net device are refcounted. Over the years we had numerous bugs caused by imbalanced dev_hold() and dev_put() calls. The general idea is to be able to precisely pair each decrement with a corresponding prior increment. Both share a cookie, basically a pointer to private data storing stack traces. This patch adds dev_hold_track() and dev_put_track(). To use these helpers, each data structure owning a refcount should also use a "netdevice_tracker" to pair the hold and put. netdevice_tracker dev_tracker; ... dev_hold_track(dev, &dev_tracker, GFP_ATOMIC); ... dev_put_track(dev, &dev_tracker); Whenever a leak happens, we will get precise stack traces of the point dev_hold_track() happened, at device dismantle phase. We will also get a stack trace if too many dev_put_track() for the same netdevice_tracker are attempted. This is guarded by CONFIG_NET_DEV_REFCNT_TRACKER option. Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
914a7b5000
commit
4d92b95ff2
@@ -9864,6 +9864,7 @@ static void netdev_wait_allrefs(struct net_device *dev)
|
||||
netdev_unregister_timeout_secs * HZ)) {
|
||||
pr_emerg("unregister_netdevice: waiting for %s to become free. Usage count = %d\n",
|
||||
dev->name, refcnt);
|
||||
ref_tracker_dir_print(&dev->refcnt_tracker, 10);
|
||||
warning_time = jiffies;
|
||||
}
|
||||
}
|
||||
@@ -10154,6 +10155,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
|
||||
dev = PTR_ALIGN(p, NETDEV_ALIGN);
|
||||
dev->padded = (char *)dev - (char *)p;
|
||||
|
||||
ref_tracker_dir_init(&dev->refcnt_tracker, 128);
|
||||
#ifdef CONFIG_PCPU_DEV_REFCNT
|
||||
dev->pcpu_refcnt = alloc_percpu(int);
|
||||
if (!dev->pcpu_refcnt)
|
||||
@@ -10270,6 +10272,7 @@ void free_netdev(struct net_device *dev)
|
||||
list_for_each_entry_safe(p, n, &dev->napi_list, dev_list)
|
||||
netif_napi_del(p);
|
||||
|
||||
ref_tracker_dir_exit(&dev->refcnt_tracker);
|
||||
#ifdef CONFIG_PCPU_DEV_REFCNT
|
||||
free_percpu(dev->pcpu_refcnt);
|
||||
dev->pcpu_refcnt = NULL;
|
||||
|
||||
Reference in New Issue
Block a user