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

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

IPoIB: Avoid free_netdev() BUG when destroying a child interface



We have to release the RTNL before calling free_netdev() so that the
device state has a chance to become NETREG_UNREGISTERED.  Otherwise
when removing a child interface, we hit the BUG() that tests the
device state in free_netdev().

Reported-by: default avatarYossi Etigin <yosefe@voltaire.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent 5d80f8e5
Loading
Loading
Loading
Loading
+15 −10
Original line number Diff line number Diff line
@@ -70,12 +70,14 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
	 */
	if (ppriv->pkey == pkey) {
		result = -ENOTUNIQ;
		priv = NULL;
		goto err;
	}

	list_for_each_entry(priv, &ppriv->child_intfs, list) {
		if (priv->pkey == pkey) {
			result = -ENOTUNIQ;
			priv = NULL;
			goto err;
		}
	}
@@ -96,7 +98,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)

	result = ipoib_set_dev_features(priv, ppriv->ca);
	if (result)
		goto device_init_failed;
		goto err;

	priv->pkey = pkey;

@@ -109,7 +111,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
		ipoib_warn(ppriv, "failed to initialize subinterface: "
			   "device %s, port %d",
			   ppriv->ca->name, ppriv->port);
		goto device_init_failed;
		goto err;
	}

	result = register_netdevice(priv->dev);
@@ -146,19 +148,19 @@ sysfs_failed:
register_failed:
	ipoib_dev_cleanup(priv->dev);

device_init_failed:
	free_netdev(priv->dev);

err:
	mutex_unlock(&ppriv->vlan_mutex);
	rtnl_unlock();
	if (priv)
		free_netdev(priv->dev);

	return result;
}

int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
{
	struct ipoib_dev_priv *ppriv, *priv, *tpriv;
	int ret = -ENOENT;
	struct net_device *dev = NULL;

	if (!capable(CAP_NET_ADMIN))
		return -EPERM;
@@ -172,14 +174,17 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
			unregister_netdevice(priv->dev);
			ipoib_dev_cleanup(priv->dev);
			list_del(&priv->list);
			free_netdev(priv->dev);

			ret = 0;
			dev = priv->dev;
			break;
		}
	}
	mutex_unlock(&ppriv->vlan_mutex);
	rtnl_unlock();

	return ret;
	if (dev) {
		free_netdev(dev);
		return 0;
	}

	return -ENODEV;
}