aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShalom Lagziel <shaloml@mellanox.com>2017-09-24 14:46:32 -0400
committerDoug Ledford <dledford@redhat.com>2017-09-25 11:47:23 -0400
commit9c6f42e9254150d2772242d9f8bd8d0b7b7431ff (patch)
tree21ae36b5cd27156f07541442822bbf3bd0499f15
parentedd31551148c09608feee6b8756ad148d550ee3b (diff)
IB/ipoib: Fix sysfs Pkey create<->remove possible deadlock
A possible ABBA lock can happen with RTNL and vlan_rwsem. For example: Flow A: Device Flush __ipoib_ib_dev_flush down_read(vlan_rwsem) // Lock A ipoib_flush_ah flush_workqueue(priv->wq) // Wait for completion A work on shared WQ (Mcast carrier) ipoib_mcast_carrier_on_task while (!rtnl_trylock()) // Wait for lock B Flow B: Sysfs PKEY delete ipoib_vlan_delete lock(RTNL) // Lock B down_write(vlan_rwsem) // Wait for lock A This can happen with PKEY creates as well. The solution is to release the RTNL lock in sysfs functions in case it is not possible to lock VLAN RW semaphore and reset the SYS call. Fixes: 69956d83267e ("IB/ipoib: Sync between remove_one to sysfs calls that use rtnl_lock") Signed-off-by: Shalom Lagziel <shaloml@mellanox.com> Signed-off-by: Alex Vesker <valex@mellanox.com> Signed-off-by: Leon Romanovsky <leon@kernel.org> Signed-off-by: Doug Ledford <dledford@redhat.com>
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_vlan.c20
1 files changed, 14 insertions, 6 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index 9927cd6b7082..e01c58edca15 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -141,14 +141,17 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
141 return restart_syscall(); 141 return restart_syscall();
142 } 142 }
143 143
144 priv = ipoib_intf_alloc(ppriv->ca, ppriv->port, intf_name); 144 if (!down_write_trylock(&ppriv->vlan_rwsem)) {
145 if (!priv) {
146 rtnl_unlock(); 145 rtnl_unlock();
147 mutex_unlock(&ppriv->sysfs_mutex); 146 mutex_unlock(&ppriv->sysfs_mutex);
148 return -ENOMEM; 147 return restart_syscall();
149 } 148 }
150 149
151 down_write(&ppriv->vlan_rwsem); 150 priv = ipoib_intf_alloc(ppriv->ca, ppriv->port, intf_name);
151 if (!priv) {
152 result = -ENOMEM;
153 goto out;
154 }
152 155
153 /* 156 /*
154 * First ensure this isn't a duplicate. We check the parent device and 157 * First ensure this isn't a duplicate. We check the parent device and
@@ -175,7 +178,7 @@ out:
175 rtnl_unlock(); 178 rtnl_unlock();
176 mutex_unlock(&ppriv->sysfs_mutex); 179 mutex_unlock(&ppriv->sysfs_mutex);
177 180
178 if (result) { 181 if (result && priv) {
179 free_netdev(priv->dev); 182 free_netdev(priv->dev);
180 kfree(priv); 183 kfree(priv);
181 } 184 }
@@ -204,7 +207,12 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
204 return restart_syscall(); 207 return restart_syscall();
205 } 208 }
206 209
207 down_write(&ppriv->vlan_rwsem); 210 if (!down_write_trylock(&ppriv->vlan_rwsem)) {
211 rtnl_unlock();
212 mutex_unlock(&ppriv->sysfs_mutex);
213 return restart_syscall();
214 }
215
208 list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) { 216 list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
209 if (priv->pkey == pkey && 217 if (priv->pkey == pkey &&
210 priv->child_type == IPOIB_LEGACY_CHILD) { 218 priv->child_type == IPOIB_LEGACY_CHILD) {