Skip to content

Commit cbbe1ef

Browse files
author
Roland Dreier
committed
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: Yossi Etigin <[email protected]> Signed-off-by: Roland Dreier <[email protected]>
1 parent b8a1b1c commit cbbe1ef

File tree

1 file changed

+8
-3
lines changed

1 file changed

+8
-3
lines changed

drivers/infiniband/ulp/ipoib/ipoib_vlan.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
6161

6262
ppriv = netdev_priv(pdev);
6363

64+
rtnl_lock();
6465
mutex_lock(&ppriv->vlan_mutex);
6566

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

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

136137
mutex_unlock(&ppriv->vlan_mutex);
138+
rtnl_unlock();
137139

138140
return 0;
139141

140142
sysfs_failed:
141143
ipoib_delete_debug_files(priv->dev);
142-
unregister_netdev(priv->dev);
144+
unregister_netdevice(priv->dev);
143145

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

150152
err:
151153
mutex_unlock(&ppriv->vlan_mutex);
154+
rtnl_unlock();
152155
return result;
153156
}
154157

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

163166
ppriv = netdev_priv(pdev);
164167

168+
rtnl_lock();
165169
mutex_lock(&ppriv->vlan_mutex);
166170
list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
167171
if (priv->pkey == pkey) {
168-
unregister_netdev(priv->dev);
172+
unregister_netdevice(priv->dev);
169173
ipoib_dev_cleanup(priv->dev);
170174
list_del(&priv->list);
171175
free_netdev(priv->dev);
@@ -175,6 +179,7 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
175179
}
176180
}
177181
mutex_unlock(&ppriv->vlan_mutex);
182+
rtnl_unlock();
178183

179184
return ret;
180185
}

0 commit comments

Comments
 (0)