aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland Dreier <rolandd@cisco.com>2009-03-31 13:22:32 -0400
committerRoland Dreier <rolandd@cisco.com>2009-03-31 13:22:32 -0400
commitedb5abb1e2a84fd8802a3577d95eac84fe1405ab (patch)
treea1337e312058581acada61502ccee9ff99c28f96
parent5d80f8e5a9dc9c9a94d4aeaa567e219a808b8a4a (diff)
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: Yossi Etigin <yosefe@voltaire.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_vlan.c25
1 files changed, 15 insertions, 10 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index 5a76a5510350..4c57f329dd50 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -70,12 +70,14 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
70 */ 70 */
71 if (ppriv->pkey == pkey) { 71 if (ppriv->pkey == pkey) {
72 result = -ENOTUNIQ; 72 result = -ENOTUNIQ;
73 priv = NULL;
73 goto err; 74 goto err;
74 } 75 }
75 76
76 list_for_each_entry(priv, &ppriv->child_intfs, list) { 77 list_for_each_entry(priv, &ppriv->child_intfs, list) {
77 if (priv->pkey == pkey) { 78 if (priv->pkey == pkey) {
78 result = -ENOTUNIQ; 79 result = -ENOTUNIQ;
80 priv = NULL;
79 goto err; 81 goto err;
80 } 82 }
81 } 83 }
@@ -96,7 +98,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
96 98
97 result = ipoib_set_dev_features(priv, ppriv->ca); 99 result = ipoib_set_dev_features(priv, ppriv->ca);
98 if (result) 100 if (result)
99 goto device_init_failed; 101 goto err;
100 102
101 priv->pkey = pkey; 103 priv->pkey = pkey;
102 104
@@ -109,7 +111,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
109 ipoib_warn(ppriv, "failed to initialize subinterface: " 111 ipoib_warn(ppriv, "failed to initialize subinterface: "
110 "device %s, port %d", 112 "device %s, port %d",
111 ppriv->ca->name, ppriv->port); 113 ppriv->ca->name, ppriv->port);
112 goto device_init_failed; 114 goto err;
113 } 115 }
114 116
115 result = register_netdevice(priv->dev); 117 result = register_netdevice(priv->dev);
@@ -146,19 +148,19 @@ sysfs_failed:
146register_failed: 148register_failed:
147 ipoib_dev_cleanup(priv->dev); 149 ipoib_dev_cleanup(priv->dev);
148 150
149device_init_failed:
150 free_netdev(priv->dev);
151
152err: 151err:
153 mutex_unlock(&ppriv->vlan_mutex); 152 mutex_unlock(&ppriv->vlan_mutex);
154 rtnl_unlock(); 153 rtnl_unlock();
154 if (priv)
155 free_netdev(priv->dev);
156
155 return result; 157 return result;
156} 158}
157 159
158int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey) 160int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
159{ 161{
160 struct ipoib_dev_priv *ppriv, *priv, *tpriv; 162 struct ipoib_dev_priv *ppriv, *priv, *tpriv;
161 int ret = -ENOENT; 163 struct net_device *dev = NULL;
162 164
163 if (!capable(CAP_NET_ADMIN)) 165 if (!capable(CAP_NET_ADMIN))
164 return -EPERM; 166 return -EPERM;
@@ -172,14 +174,17 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
172 unregister_netdevice(priv->dev); 174 unregister_netdevice(priv->dev);
173 ipoib_dev_cleanup(priv->dev); 175 ipoib_dev_cleanup(priv->dev);
174 list_del(&priv->list); 176 list_del(&priv->list);
175 free_netdev(priv->dev); 177 dev = priv->dev;
176
177 ret = 0;
178 break; 178 break;
179 } 179 }
180 } 180 }
181 mutex_unlock(&ppriv->vlan_mutex); 181 mutex_unlock(&ppriv->vlan_mutex);
182 rtnl_unlock(); 182 rtnl_unlock();
183 183
184 return ret; 184 if (dev) {
185 free_netdev(dev);
186 return 0;
187 }
188
189 return -ENODEV;
185} 190}