diff mbox series

[rdma-nxt] i40iw: Do an RCU lookup in i40iw_add_ipv4_addr

Message ID 20200117214720.1960-1-shiraz.saleem@intel.com (mailing list archive)
State Superseded
Headers show
Series [rdma-nxt] i40iw: Do an RCU lookup in i40iw_add_ipv4_addr | expand

Commit Message

Saleem, Shiraz Jan. 17, 2020, 9:47 p.m. UTC
From: "Shiraz Saleem" <shiraz.saleem@intel.com>

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 since there are
no netdev object updates in this function.

Fixes: 8e06af711bf2 ("i40iw: add main, hdr, status")
Signed-off-by: Shiraz Saleem <shiraz.saleem@intel.com>
---
 drivers/infiniband/hw/i40iw/i40iw_main.c | 16 +++++-----------
 1 file changed, 5 insertions(+), 11 deletions(-)

Comments

Jason Gunthorpe Jan. 25, 2020, 6:31 p.m. UTC | #1
On Fri, Jan 17, 2020 at 03:47:20PM -0600, Shiraz Saleem wrote:
> From: "Shiraz Saleem" <shiraz.saleem@intel.com>
> 
> 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 since there are
> no netdev object updates in this function.
> 
> Fixes: 8e06af711bf2 ("i40iw: add main, hdr, status")
> Signed-off-by: Shiraz Saleem <shiraz.saleem@intel.com>
> ---
>  drivers/infiniband/hw/i40iw/i40iw_main.c | 16 +++++-----------
>  1 file changed, 5 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c
> index 2386143..d7a1219 100644
> --- a/drivers/infiniband/hw/i40iw/i40iw_main.c
> +++ b/drivers/infiniband/hw/i40iw/i40iw_main.c
> @@ -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)) {
>  			const struct in_ifaddr *ifa;

The rtnl does not just protect the pointers, but also values like
flags from changing. When using RCU any varient values of the dev
should be read with READ_ONCE, such as flags.

I'm not completely sure the vlan tests are OK under RCU either, but
netdev has historically been loose on its READ_ONCE/WRITE_ONCE
annotations..

Jason
diff mbox series

Patch

diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c
index 2386143..d7a1219 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_main.c
+++ b/drivers/infiniband/hw/i40iw/i40iw_main.c
@@ -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)) {
 			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();
 }
 
 /**