net: debug lo refcnt From: Konstantin Khlebnikov Signed-off-by: Konstantin Khlebnikov --- include/linux/netdevice.h | 4 ++++ net/core/dev.c | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 310e729c47a4..b483b0eb22e7 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3141,6 +3141,8 @@ extern int netdev_budget; /* Called by rtnetlink.c:rtnl_unlock() */ void netdev_run_todo(void); +void netdev_refcnt_log(const struct net_device *dev, char op); + /** * dev_put - release reference to device * @dev: network device @@ -3150,6 +3152,7 @@ void netdev_run_todo(void); static inline void dev_put(struct net_device *dev) { this_cpu_dec(*dev->pcpu_refcnt); + netdev_refcnt_log(dev, '-'); } /** @@ -3161,6 +3164,7 @@ static inline void dev_put(struct net_device *dev) static inline void dev_hold(struct net_device *dev) { this_cpu_inc(*dev->pcpu_refcnt); + netdev_refcnt_log(dev, '+'); } /* Carrier loss detection, dial on demand. The functions netif_carrier_on diff --git a/net/core/dev.c b/net/core/dev.c index 2e47d40388fc..d56c834140c8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6957,6 +6957,20 @@ int netdev_refcnt_read(const struct net_device *dev) } EXPORT_SYMBOL(netdev_refcnt_read); +void netdev_refcnt_log(const struct net_device *dev, char op) +{ + static DEFINE_SPINLOCK(lock); + unsigned long flags; + + if ((dev->flags & IFF_LOOPBACK) && !net_eq(dev_net(dev), &init_net)) { + spin_lock_irqsave(&lock, flags); + printk("%c %p %d\n", op, dev, netdev_refcnt_read(dev)); + dump_stack(); + spin_unlock_irqrestore(&lock, flags); + } +} +EXPORT_SYMBOL(netdev_refcnt_log); + /** * netdev_wait_allrefs - wait until all references are gone. * @dev: target net_device