Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cbbe1efa authored by Roland Dreier's avatar Roland Dreier
Browse files

IPoIB: Fix deadlock between ipoib_open() and child interface create



Fix a deadlock between child interface creation/deletion and ipoib
start/stop.  The former takes vlan_mutex, and then might take RTNL via
register_netdev()/unregister_netdev().  The latter is executed with
RTNL held, and tries to take vlan_mutex, which can lead to an AB-BA
deadlock.

Fix this by having the child interface creation/deletion code take the
RTNL first so vlan_mutex always nests inside RTNL.  We can use
register_netdevice() for child interfaces because we form the
interface name from the parent interface and hence don't need the '%'
expansion of register_netdev().

Reported-by: default avatarYossi Etigin <yosefe@voltaire.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent b8a1b1ce
Loading
Loading
Loading
Loading
+8 −3
Original line number Original line Diff line number Diff line
@@ -61,6 +61,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)


	ppriv = netdev_priv(pdev);
	ppriv = netdev_priv(pdev);


	rtnl_lock();
	mutex_lock(&ppriv->vlan_mutex);
	mutex_lock(&ppriv->vlan_mutex);


	/*
	/*
@@ -111,7 +112,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
		goto device_init_failed;
		goto device_init_failed;
	}
	}


	result = register_netdev(priv->dev);
	result = register_netdevice(priv->dev);
	if (result) {
	if (result) {
		ipoib_warn(priv, "failed to initialize; error %i", result);
		ipoib_warn(priv, "failed to initialize; error %i", result);
		goto register_failed;
		goto register_failed;
@@ -134,12 +135,13 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
	list_add_tail(&priv->list, &ppriv->child_intfs);
	list_add_tail(&priv->list, &ppriv->child_intfs);


	mutex_unlock(&ppriv->vlan_mutex);
	mutex_unlock(&ppriv->vlan_mutex);
	rtnl_unlock();


	return 0;
	return 0;


sysfs_failed:
sysfs_failed:
	ipoib_delete_debug_files(priv->dev);
	ipoib_delete_debug_files(priv->dev);
	unregister_netdev(priv->dev);
	unregister_netdevice(priv->dev);


register_failed:
register_failed:
	ipoib_dev_cleanup(priv->dev);
	ipoib_dev_cleanup(priv->dev);
@@ -149,6 +151,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)


err:
err:
	mutex_unlock(&ppriv->vlan_mutex);
	mutex_unlock(&ppriv->vlan_mutex);
	rtnl_unlock();
	return result;
	return result;
}
}


@@ -162,10 +165,11 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)


	ppriv = netdev_priv(pdev);
	ppriv = netdev_priv(pdev);


	rtnl_lock();
	mutex_lock(&ppriv->vlan_mutex);
	mutex_lock(&ppriv->vlan_mutex);
	list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
	list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
		if (priv->pkey == pkey) {
		if (priv->pkey == pkey) {
			unregister_netdev(priv->dev);
			unregister_netdevice(priv->dev);
			ipoib_dev_cleanup(priv->dev);
			ipoib_dev_cleanup(priv->dev);
			list_del(&priv->list);
			list_del(&priv->list);
			free_netdev(priv->dev);
			free_netdev(priv->dev);
@@ -175,6 +179,7 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
		}
		}
	}
	}
	mutex_unlock(&ppriv->vlan_mutex);
	mutex_unlock(&ppriv->vlan_mutex);
	rtnl_unlock();


	return ret;
	return ret;
}
}