i40iw: Do an RCU lookup in i40iw_add_ipv4_addr
authorShiraz Saleem <shiraz.saleem@intel.com>
Tue, 4 Feb 2020 22:38:40 +0000 (16:38 -0600)
committerJason Gunthorpe <jgg@mellanox.com>
Tue, 11 Feb 2020 18:31:11 +0000 (14:31 -0400)
The in_dev_for_each_ifa_rtnl() iterator in i40iw_add_ipv4_addr requires
that the rtnl lock be held. But the rtnl_trylock/unlock scheme in this
function does not guarantee it.

Replace the rtnl locking with an RCU lookup using
in_dev_for_each_ifa_rcu()

Fixes: 8e06af711bf2 ("i40iw: add main, hdr, status")
Link: https://lore.kernel.org/r/20200204223840.2151-1-shiraz.saleem@intel.com
Signed-off-by: Shiraz Saleem <shiraz.saleem@intel.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
drivers/infiniband/hw/i40iw/i40iw_main.c

index 2386143..84e1b52 100644 (file)
@@ -1212,22 +1212,19 @@ static void i40iw_add_ipv4_addr(struct i40iw_device *iwdev)
 {
        struct net_device *dev;
        struct in_device *idev;
-       bool got_lock = true;
        u32 ip_addr;
 
-       if (!rtnl_trylock())
-               got_lock = false;
-
-       for_each_netdev(&init_net, dev) {
+       rcu_read_lock();
+       for_each_netdev_rcu(&init_net, dev) {
                if ((((rdma_vlan_dev_vlan_id(dev) < 0xFFFF) &&
                      (rdma_vlan_dev_real_dev(dev) == iwdev->netdev)) ||
-                   (dev == iwdev->netdev)) && (dev->flags & IFF_UP)) {
+                   (dev == iwdev->netdev)) && (READ_ONCE(dev->flags) & IFF_UP)) {
                        const struct in_ifaddr *ifa;
 
-                       idev = in_dev_get(dev);
+                       idev = __in_dev_get_rcu(dev);
                        if (!idev)
                                continue;
-                       in_dev_for_each_ifa_rtnl(ifa, idev) {
+                       in_dev_for_each_ifa_rcu(ifa, idev) {
                                i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_CM,
                                            "IP=%pI4, vlan_id=%d, MAC=%pM\n", &ifa->ifa_address,
                                             rdma_vlan_dev_vlan_id(dev), dev->dev_addr);
@@ -1239,12 +1236,9 @@ static void i40iw_add_ipv4_addr(struct i40iw_device *iwdev)
                                                       true,
                                                       I40IW_ARP_ADD);
                        }
-
-                       in_dev_put(idev);
                }
        }
-       if (got_lock)
-               rtnl_unlock();
+       rcu_read_unlock();
 }
 
 /**