IPoIB: Fix deadlock between dev_change_flags() and __ipoib_dev_flush()
[cascardo/linux.git] / drivers / infiniband / ulp / ipoib / ipoib_ib.c
index 196b1d1..01594de 100644 (file)
@@ -685,15 +685,13 @@ int ipoib_ib_dev_open(struct net_device *dev)
        ret = ipoib_ib_post_receives(dev);
        if (ret) {
                ipoib_warn(priv, "ipoib_ib_post_receives returned %d\n", ret);
-               ipoib_ib_dev_stop(dev, 1);
-               return -1;
+               goto dev_stop;
        }
 
        ret = ipoib_cm_dev_open(dev);
        if (ret) {
                ipoib_warn(priv, "ipoib_cm_dev_open returned %d\n", ret);
-               ipoib_ib_dev_stop(dev, 1);
-               return -1;
+               goto dev_stop;
        }
 
        clear_bit(IPOIB_STOP_REAPER, &priv->flags);
@@ -704,6 +702,11 @@ int ipoib_ib_dev_open(struct net_device *dev)
                napi_enable(&priv->napi);
 
        return 0;
+dev_stop:
+       if (!test_and_set_bit(IPOIB_FLAG_INITIALIZED, &priv->flags))
+               napi_enable(&priv->napi);
+       ipoib_ib_dev_stop(dev, 1);
+       return -1;
 }
 
 static void ipoib_pkey_dev_check_presence(struct net_device *dev)
@@ -974,7 +977,7 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
        u16 new_index;
        int result;
 
-       mutex_lock(&priv->vlan_mutex);
+       down_read(&priv->vlan_rwsem);
 
        /*
         * Flush any child interfaces too -- they might be up even if
@@ -983,7 +986,7 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
        list_for_each_entry(cpriv, &priv->child_intfs, list)
                __ipoib_ib_dev_flush(cpriv, level);
 
-       mutex_unlock(&priv->vlan_mutex);
+       up_read(&priv->vlan_rwsem);
 
        if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) {
                /* for non-child devices must check/update the pkey value here */