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

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
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -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
 * and _off may be called from IRQ context, but it is caller
 * who is responsible for serialization of these calls.
+1 −0
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ struct dst_entry {
#ifndef CONFIG_64BIT
	atomic_t		__refcnt;	/* 32-bit offset 64 */
#endif
	netdevice_tracker	dev_tracker;
};

struct dst_metrics {
+4 −4
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@ void dst_init(struct dst_entry *dst, struct dst_ops *ops,
	      unsigned short flags)
{
	dst->dev = dev;
	dev_hold(dev);
	dev_hold_track(dev, &dst->dev_tracker, GFP_ATOMIC);
	dst->ops = ops;
	dst_init_metrics(dst, dst_default_metrics.metrics, true);
	dst->expires = 0UL;
@@ -117,7 +117,7 @@ struct dst_entry *dst_destroy(struct dst_entry * dst)

	if (dst->ops->destroy)
		dst->ops->destroy(dst);
	dev_put(dst->dev);
	dev_put_track(dst->dev, &dst->dev_tracker);

	lwtstate_put(dst->lwtstate);

@@ -159,8 +159,8 @@ void dst_dev_put(struct dst_entry *dst)
	dst->input = dst_discard;
	dst->output = dst_discard_out;
	dst->dev = blackhole_netdev;
	dev_hold(dst->dev);
	dev_put(dev);
	dev_replace_track(dev, blackhole_netdev, &dst->dev_tracker,
			  GFP_ATOMIC);
}
EXPORT_SYMBOL(dst_dev_put);

+4 −3
Original line number Diff line number Diff line
@@ -1531,8 +1531,9 @@ void rt_flush_dev(struct net_device *dev)
			if (rt->dst.dev != dev)
				continue;
			rt->dst.dev = blackhole_netdev;
			dev_hold(rt->dst.dev);
			dev_put(dev);
			dev_replace_track(dev, blackhole_netdev,
					  &rt->dst.dev_tracker,
					  GFP_ATOMIC);
		}
		spin_unlock_bh(&ul->lock);
	}
@@ -2819,7 +2820,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
		new->output = dst_discard_out;

		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_iif = ort->rt_iif;
+3 −2
Original line number Diff line number Diff line
@@ -182,8 +182,9 @@ static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)

			if (rt_dev == dev) {
				rt->dst.dev = blackhole_netdev;
				dev_hold(rt->dst.dev);
				dev_put(rt_dev);
				dev_replace_track(rt_dev, blackhole_netdev,
						  &rt->dst.dev_tracker,
						  GFP_ATOMIC);
			}
		}
		spin_unlock_bh(&ul->lock);