RDMA: Add netdevice_tracker to ib_device_set_netdev()
authorJason Gunthorpe <jgg@nvidia.com>
Thu, 24 Nov 2022 00:27:14 +0000 (20:27 -0400)
committerLeon Romanovsky <leon@kernel.org>
Mon, 28 Nov 2022 09:58:19 +0000 (11:58 +0200)
This will cause an informative backtrace to print if the user of
ib_device_set_netdev() isn't careful about tearing down the ibdevice
before its the netdevice parent is destroyed. Such as like this:

  unregister_netdevice: waiting for vlan0 to become free. Usage count = 2
  leaked reference.
   ib_device_set_netdev+0x266/0x730
   siw_newlink+0x4e0/0xfd0
   nldev_newlink+0x35c/0x5c0
   rdma_nl_rcv_msg+0x36d/0x690
   rdma_nl_rcv+0x2ee/0x430
   netlink_unicast+0x543/0x7f0
   netlink_sendmsg+0x918/0xe20
   sock_sendmsg+0xcf/0x120
   ____sys_sendmsg+0x70d/0x8b0
   ___sys_sendmsg+0x11d/0x1b0
   __sys_sendmsg+0xfa/0x1d0
   do_syscall_64+0x35/0xb0
   entry_SYSCALL_64_after_hwframe+0x63/0xcd

This will help debug the issues syzkaller is seeing.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Link: https://lore.kernel.org/r/0-v1-a7c81b3842ce+e5-netdev_tracker_jgg@nvidia.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
drivers/infiniband/core/device.c
include/rdma/ib_verbs.h

index 3409c55ea88bff3a753905a22b2fa69807890736..ff35cebb25e265ec83c318e8b0138c132c484323 100644 (file)
@@ -2159,14 +2159,16 @@ int ib_device_set_netdev(struct ib_device *ib_dev, struct net_device *ndev,
                return 0;
        }
 
+       if (old_ndev)
+               netdev_tracker_free(ndev, &pdata->netdev_tracker);
        if (ndev)
-               dev_hold(ndev);
+               netdev_hold(ndev, &pdata->netdev_tracker, GFP_ATOMIC);
        rcu_assign_pointer(pdata->netdev, ndev);
        spin_unlock_irqrestore(&pdata->netdev_lock, flags);
 
        add_ndev_hash(pdata);
        if (old_ndev)
-               dev_put(old_ndev);
+               __dev_put(old_ndev);
 
        return 0;
 }
index a1f4d53a4bb63640d73c79486761f408e7d7604d..77dd9148815b9c8f336e9c101cd36e3cf828f869 100644 (file)
@@ -2203,6 +2203,7 @@ struct ib_port_data {
        struct ib_port_cache cache;
 
        struct net_device __rcu *netdev;
+       netdevice_tracker netdev_tracker;
        struct hlist_node ndev_hash_link;
        struct rdma_port_counter port_counter;
        struct ib_port *sysfs;