aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
diff options
context:
space:
mode:
authorRoland Dreier <rolandd@cisco.com>2008-08-19 15:01:32 -0700
committerRoland Dreier <rolandd@cisco.com>2008-08-19 15:01:32 -0700
commita77a57a1a22afc31891d95879fe3cf2ab03838b0 (patch)
tree14f0b4a4e50f4e112d3189c75357e34829d78704 /drivers/infiniband/ulp/ipoib/ipoib_multicast.c
parentMerge branch 'release-2.6.27' of git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-acpi-2.6 (diff)
downloadlinux-dev-a77a57a1a22afc31891d95879fe3cf2ab03838b0.tar.xz
linux-dev-a77a57a1a22afc31891d95879fe3cf2ab03838b0.zip
IPoIB: Fix deadlock on RTNL in ipoib_stop()
Commit c8c2afe3 ("IPoIB: Use rtnl lock/unlock when changing device flags") added a call to rtnl_lock() in ipoib_mcast_join_task(), which is run from the ipoib_workqueue. However, ipoib_stop() (which is run inside rtnl_lock()) flushes this workqueue, which leads to a deadlock if the join task is pending. Fix this by simply not flushing the workqueue from ipoib_stop(). It turns out that we really don't care about workqueue tasks running during or after ipoib_stop(), as long as we make sure to flush the workqueue before unregistering a netdev. This fixes <https://bugs.openfabrics.org/show_bug.cgi?id=1114>. Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/ulp/ipoib/ipoib_multicast.c')
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index 8950e9546f4e..ac33c8f3ea85 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -392,8 +392,16 @@ static int ipoib_mcast_join_complete(int status,
&priv->mcast_task, 0);
mutex_unlock(&mcast_mutex);
- if (mcast == priv->broadcast)
+ if (mcast == priv->broadcast) {
+ /*
+ * Take RTNL lock here to avoid racing with
+ * ipoib_stop() and turning the carrier back
+ * on while a device is being removed.
+ */
+ rtnl_lock();
netif_carrier_on(dev);
+ rtnl_unlock();
+ }
return 0;
}