mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 10:57:46 +00:00
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: 69956d8326
("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>
This commit is contained in:
parent
edd3155114
commit
9c6f42e925
1 changed files with 14 additions and 6 deletions
|
@ -141,14 +141,17 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
|
||||||
return restart_syscall();
|
return restart_syscall();
|
||||||
}
|
}
|
||||||
|
|
||||||
priv = ipoib_intf_alloc(ppriv->ca, ppriv->port, intf_name);
|
if (!down_write_trylock(&ppriv->vlan_rwsem)) {
|
||||||
if (!priv) {
|
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
mutex_unlock(&ppriv->sysfs_mutex);
|
mutex_unlock(&ppriv->sysfs_mutex);
|
||||||
return -ENOMEM;
|
return restart_syscall();
|
||||||
}
|
}
|
||||||
|
|
||||||
down_write(&ppriv->vlan_rwsem);
|
priv = ipoib_intf_alloc(ppriv->ca, ppriv->port, intf_name);
|
||||||
|
if (!priv) {
|
||||||
|
result = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First ensure this isn't a duplicate. We check the parent device and
|
* First ensure this isn't a duplicate. We check the parent device and
|
||||||
|
@ -175,7 +178,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
mutex_unlock(&ppriv->sysfs_mutex);
|
mutex_unlock(&ppriv->sysfs_mutex);
|
||||||
|
|
||||||
if (result) {
|
if (result && priv) {
|
||||||
free_netdev(priv->dev);
|
free_netdev(priv->dev);
|
||||||
kfree(priv);
|
kfree(priv);
|
||||||
}
|
}
|
||||||
|
@ -204,7 +207,12 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
|
||||||
return restart_syscall();
|
return restart_syscall();
|
||||||
}
|
}
|
||||||
|
|
||||||
down_write(&ppriv->vlan_rwsem);
|
if (!down_write_trylock(&ppriv->vlan_rwsem)) {
|
||||||
|
rtnl_unlock();
|
||||||
|
mutex_unlock(&ppriv->sysfs_mutex);
|
||||||
|
return restart_syscall();
|
||||||
|
}
|
||||||
|
|
||||||
list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
|
list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
|
||||||
if (priv->pkey == pkey &&
|
if (priv->pkey == pkey &&
|
||||||
priv->child_type == IPOIB_LEGACY_CHILD) {
|
priv->child_type == IPOIB_LEGACY_CHILD) {
|
||||||
|
|
Loading…
Reference in a new issue