diff options
author | Roland Dreier <rolandd@cisco.com> | 2009-01-15 00:44:39 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2009-01-15 00:44:39 -0500 |
commit | cbbe1efa4972350286b52cb48aefaa11e198c0fb (patch) | |
tree | ddcfdea04829b9d2f84b0e9d6a9adc6eb86a5f13 /drivers/infiniband/ulp | |
parent | b8a1b1ce14252b59b2d5c89de25b54f9bfd4cc5e (diff) |
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 <yosefe@voltaire.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/ulp')
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_vlan.c | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index 2cf1a4088718..5a76a5510350 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c | |||
@@ -61,6 +61,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) | |||
61 | 61 | ||
62 | ppriv = netdev_priv(pdev); | 62 | ppriv = netdev_priv(pdev); |
63 | 63 | ||
64 | rtnl_lock(); | ||
64 | mutex_lock(&ppriv->vlan_mutex); | 65 | mutex_lock(&ppriv->vlan_mutex); |
65 | 66 | ||
66 | /* | 67 | /* |
@@ -111,7 +112,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) | |||
111 | goto device_init_failed; | 112 | goto device_init_failed; |
112 | } | 113 | } |
113 | 114 | ||
114 | result = register_netdev(priv->dev); | 115 | result = register_netdevice(priv->dev); |
115 | if (result) { | 116 | if (result) { |
116 | ipoib_warn(priv, "failed to initialize; error %i", result); | 117 | ipoib_warn(priv, "failed to initialize; error %i", result); |
117 | goto register_failed; | 118 | goto register_failed; |
@@ -134,12 +135,13 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) | |||
134 | list_add_tail(&priv->list, &ppriv->child_intfs); | 135 | list_add_tail(&priv->list, &ppriv->child_intfs); |
135 | 136 | ||
136 | mutex_unlock(&ppriv->vlan_mutex); | 137 | mutex_unlock(&ppriv->vlan_mutex); |
138 | rtnl_unlock(); | ||
137 | 139 | ||
138 | return 0; | 140 | return 0; |
139 | 141 | ||
140 | sysfs_failed: | 142 | sysfs_failed: |
141 | ipoib_delete_debug_files(priv->dev); | 143 | ipoib_delete_debug_files(priv->dev); |
142 | unregister_netdev(priv->dev); | 144 | unregister_netdevice(priv->dev); |
143 | 145 | ||
144 | register_failed: | 146 | register_failed: |
145 | ipoib_dev_cleanup(priv->dev); | 147 | ipoib_dev_cleanup(priv->dev); |
@@ -149,6 +151,7 @@ device_init_failed: | |||
149 | 151 | ||
150 | err: | 152 | err: |
151 | mutex_unlock(&ppriv->vlan_mutex); | 153 | mutex_unlock(&ppriv->vlan_mutex); |
154 | rtnl_unlock(); | ||
152 | return result; | 155 | return result; |
153 | } | 156 | } |
154 | 157 | ||
@@ -162,10 +165,11 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey) | |||
162 | 165 | ||
163 | ppriv = netdev_priv(pdev); | 166 | ppriv = netdev_priv(pdev); |
164 | 167 | ||
168 | rtnl_lock(); | ||
165 | mutex_lock(&ppriv->vlan_mutex); | 169 | mutex_lock(&ppriv->vlan_mutex); |
166 | list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) { | 170 | list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) { |
167 | if (priv->pkey == pkey) { | 171 | if (priv->pkey == pkey) { |
168 | unregister_netdev(priv->dev); | 172 | unregister_netdevice(priv->dev); |
169 | ipoib_dev_cleanup(priv->dev); | 173 | ipoib_dev_cleanup(priv->dev); |
170 | list_del(&priv->list); | 174 | list_del(&priv->list); |
171 | free_netdev(priv->dev); | 175 | free_netdev(priv->dev); |
@@ -175,6 +179,7 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey) | |||
175 | } | 179 | } |
176 | } | 180 | } |
177 | mutex_unlock(&ppriv->vlan_mutex); | 181 | mutex_unlock(&ppriv->vlan_mutex); |
182 | rtnl_unlock(); | ||
178 | 183 | ||
179 | return ret; | 184 | return ret; |
180 | } | 185 | } |