Skip to content

Commit

Permalink
IPoIB: Avoid free_netdev() BUG when destroying a child interface
Browse files Browse the repository at this point in the history
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: Yossi Etigin <yosefe@voltaire.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
  • Loading branch information
Roland Dreier committed Mar 31, 2009
1 parent 5d80f8e commit edb5abb
Showing 1 changed file with 15 additions and 10 deletions.
25 changes: 15 additions & 10 deletions drivers/infiniband/ulp/ipoib/ipoib_vlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand All @@ -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;

Expand All @@ -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);
Expand Down Expand Up @@ -146,19 +148,19 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
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;
Expand All @@ -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;
}

0 comments on commit edb5abb

Please sign in to comment.