Commit 9038c320 authored by Eric Dumazet's avatar Eric Dumazet Committed by Jakub Kicinski

net: dst: add net device refcount tracking to dst_entry

We want to track all dev_hold()/dev_put() to ease leak hunting.
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 4dbd24f6
...@@ -3883,6 +3883,23 @@ static inline void dev_put_track(struct net_device *dev, ...@@ -3883,6 +3883,23 @@ static inline void dev_put_track(struct net_device *dev,
} }
} }
static inline void dev_replace_track(struct net_device *odev,
struct net_device *ndev,
netdevice_tracker *tracker,
gfp_t gfp)
{
#ifdef CONFIG_NET_DEV_REFCNT_TRACKER
if (odev)
ref_tracker_free(&odev->refcnt_tracker, tracker);
#endif
dev_hold(ndev);
dev_put(odev);
#ifdef CONFIG_NET_DEV_REFCNT_TRACKER
if (ndev)
ref_tracker_alloc(&ndev->refcnt_tracker, tracker, gfp);
#endif
}
/* Carrier loss detection, dial on demand. The functions netif_carrier_on /* Carrier loss detection, dial on demand. The functions netif_carrier_on
* and _off may be called from IRQ context, but it is caller * and _off may be called from IRQ context, but it is caller
* who is responsible for serialization of these calls. * who is responsible for serialization of these calls.
......
...@@ -77,6 +77,7 @@ struct dst_entry { ...@@ -77,6 +77,7 @@ struct dst_entry {
#ifndef CONFIG_64BIT #ifndef CONFIG_64BIT
atomic_t __refcnt; /* 32-bit offset 64 */ atomic_t __refcnt; /* 32-bit offset 64 */
#endif #endif
netdevice_tracker dev_tracker;
}; };
struct dst_metrics { struct dst_metrics {
......
...@@ -49,7 +49,7 @@ void dst_init(struct dst_entry *dst, struct dst_ops *ops, ...@@ -49,7 +49,7 @@ void dst_init(struct dst_entry *dst, struct dst_ops *ops,
unsigned short flags) unsigned short flags)
{ {
dst->dev = dev; dst->dev = dev;
dev_hold(dev); dev_hold_track(dev, &dst->dev_tracker, GFP_ATOMIC);
dst->ops = ops; dst->ops = ops;
dst_init_metrics(dst, dst_default_metrics.metrics, true); dst_init_metrics(dst, dst_default_metrics.metrics, true);
dst->expires = 0UL; dst->expires = 0UL;
...@@ -117,7 +117,7 @@ struct dst_entry *dst_destroy(struct dst_entry * dst) ...@@ -117,7 +117,7 @@ struct dst_entry *dst_destroy(struct dst_entry * dst)
if (dst->ops->destroy) if (dst->ops->destroy)
dst->ops->destroy(dst); dst->ops->destroy(dst);
dev_put(dst->dev); dev_put_track(dst->dev, &dst->dev_tracker);
lwtstate_put(dst->lwtstate); lwtstate_put(dst->lwtstate);
...@@ -159,8 +159,8 @@ void dst_dev_put(struct dst_entry *dst) ...@@ -159,8 +159,8 @@ void dst_dev_put(struct dst_entry *dst)
dst->input = dst_discard; dst->input = dst_discard;
dst->output = dst_discard_out; dst->output = dst_discard_out;
dst->dev = blackhole_netdev; dst->dev = blackhole_netdev;
dev_hold(dst->dev); dev_replace_track(dev, blackhole_netdev, &dst->dev_tracker,
dev_put(dev); GFP_ATOMIC);
} }
EXPORT_SYMBOL(dst_dev_put); EXPORT_SYMBOL(dst_dev_put);
......
...@@ -1531,8 +1531,9 @@ void rt_flush_dev(struct net_device *dev) ...@@ -1531,8 +1531,9 @@ void rt_flush_dev(struct net_device *dev)
if (rt->dst.dev != dev) if (rt->dst.dev != dev)
continue; continue;
rt->dst.dev = blackhole_netdev; rt->dst.dev = blackhole_netdev;
dev_hold(rt->dst.dev); dev_replace_track(dev, blackhole_netdev,
dev_put(dev); &rt->dst.dev_tracker,
GFP_ATOMIC);
} }
spin_unlock_bh(&ul->lock); spin_unlock_bh(&ul->lock);
} }
...@@ -2819,7 +2820,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or ...@@ -2819,7 +2820,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
new->output = dst_discard_out; new->output = dst_discard_out;
new->dev = net->loopback_dev; new->dev = net->loopback_dev;
dev_hold(new->dev); dev_hold_track(new->dev, &new->dev_tracker, GFP_ATOMIC);
rt->rt_is_input = ort->rt_is_input; rt->rt_is_input = ort->rt_is_input;
rt->rt_iif = ort->rt_iif; rt->rt_iif = ort->rt_iif;
......
...@@ -182,8 +182,9 @@ static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev) ...@@ -182,8 +182,9 @@ static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
if (rt_dev == dev) { if (rt_dev == dev) {
rt->dst.dev = blackhole_netdev; rt->dst.dev = blackhole_netdev;
dev_hold(rt->dst.dev); dev_replace_track(rt_dev, blackhole_netdev,
dev_put(rt_dev); &rt->dst.dev_tracker,
GFP_ATOMIC);
} }
} }
spin_unlock_bh(&ul->lock); spin_unlock_bh(&ul->lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment