IPoIB: Take dev->xmit_lock around mc_list accesses
[deliverable/linux.git] / drivers / infiniband / ulp / ipoib / ipoib_multicast.c
index 3ecf78a9493a1e556f0ec2e475361de8e9c60a84..bf1c08cca8cb8cd24e0b9252b9f6330e81e8d453 100644 (file)
@@ -43,6 +43,8 @@
 #include <linux/delay.h>
 #include <linux/completion.h>
 
+#include <net/dst.h>
+
 #include "ipoib.h"
 
 #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
@@ -95,8 +97,6 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ipoib_neigh *neigh, *tmp;
        unsigned long flags;
-       LIST_HEAD(ah_list);
-       struct ipoib_ah *ah, *tah;
 
        ipoib_dbg_mcast(netdev_priv(dev),
                        "deleting multicast group " IPOIB_GID_FMT "\n",
@@ -105,8 +105,14 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
        spin_lock_irqsave(&priv->lock, flags);
 
        list_for_each_entry_safe(neigh, tmp, &mcast->neigh_list, list) {
+               /*
+                * It's safe to call ipoib_put_ah() inside priv->lock
+                * here, because we know that mcast->ah will always
+                * hold one more reference, so ipoib_put_ah() will
+                * never do more than decrement the ref count.
+                */
                if (neigh->ah)
-                       list_add_tail(&neigh->ah->list, &ah_list);
+                       ipoib_put_ah(neigh->ah);
                *to_ipoib_neigh(neigh->neighbour) = NULL;
                neigh->neighbour->ops->destructor = NULL;
                kfree(neigh);
@@ -114,18 +120,11 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       list_for_each_entry_safe(ah, tah, &ah_list, list)
-               ipoib_put_ah(ah);
-
        if (mcast->ah)
                ipoib_put_ah(mcast->ah);
 
-       while (!skb_queue_empty(&mcast->pkt_queue)) {
-               struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue);
-
-               skb->dev = dev;
-               dev_kfree_skb_any(skb);
-       }
+       while (!skb_queue_empty(&mcast->pkt_queue))
+               dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
 
        kfree(mcast);
 }
@@ -139,20 +138,14 @@ static struct ipoib_mcast *ipoib_mcast_alloc(struct net_device *dev,
        if (!mcast)
                return NULL;
 
-       init_completion(&mcast->done);
-
        mcast->dev = dev;
        mcast->created = jiffies;
        mcast->backoff = 1;
-       mcast->logcount = 0;
 
        INIT_LIST_HEAD(&mcast->list);
        INIT_LIST_HEAD(&mcast->neigh_list);
        skb_queue_head_init(&mcast->pkt_queue);
 
-       mcast->ah    = NULL;
-       mcast->query = NULL;
-
        return mcast;
 }
 
@@ -317,13 +310,8 @@ ipoib_mcast_sendonly_join_complete(int status,
                                        IPOIB_GID_ARG(mcast->mcmember.mgid), status);
 
                /* Flush out any queued packets */
-               while (!skb_queue_empty(&mcast->pkt_queue)) {
-                       struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue);
-
-                       skb->dev = dev;
-
-                       dev_kfree_skb_any(skb);
-               }
+               while (!skb_queue_empty(&mcast->pkt_queue))
+                       dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
 
                /* Clear the busy flag so we try again */
                clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
@@ -359,6 +347,8 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast)
        rec.port_gid = priv->local_gid;
        rec.pkey     = cpu_to_be16(priv->pkey);
 
+       init_completion(&mcast->done);
+
        ret = ib_sa_mcmember_rec_set(priv->ca, priv->port, &rec,
                                     IB_SA_MCMEMBER_REC_MGID            |
                                     IB_SA_MCMEMBER_REC_PORT_GID        |
@@ -478,6 +468,8 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast,
                rec.traffic_class = priv->broadcast->mcmember.traffic_class;
        }
 
+       init_completion(&mcast->done);
+
        ret = ib_sa_mcmember_rec_set(priv->ca, priv->port, &rec, comp_mask,
                                     mcast->backoff * 1000, GFP_ATOMIC,
                                     ipoib_mcast_join_complete,
@@ -789,9 +781,11 @@ void ipoib_mcast_dev_flush(struct net_device *dev)
                                        &priv->multicast_tree);
 
                        list_add_tail(&priv->broadcast->list, &remove_list);
-               }
-
-               priv->broadcast = nmcast;
+                       priv->broadcast = nmcast;
+               } else
+                       ipoib_warn(priv, "could not reallocate broadcast group "
+                                         IPOIB_GID_FMT "\n",
+                                         IPOIB_GID_ARG(priv->broadcast->mcmember.mgid));
        }
 
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -833,7 +827,8 @@ void ipoib_mcast_restart_task(void *dev_ptr)
 
        ipoib_mcast_stop_thread(dev, 0);
 
-       spin_lock_irqsave(&priv->lock, flags);
+       spin_lock_irqsave(&dev->xmit_lock, flags);
+       spin_lock(&priv->lock);
 
        /*
         * Unfortunately, the networking core only gives us a list of all of
@@ -905,7 +900,9 @@ void ipoib_mcast_restart_task(void *dev_ptr)
                        list_add_tail(&mcast->list, &remove_list);
                }
        }
-       spin_unlock_irqrestore(&priv->lock, flags);
+
+       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&dev->xmit_lock, flags);
 
        /* We have to cancel outside of the spinlock */
        list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
@@ -928,21 +925,16 @@ struct ipoib_mcast_iter *ipoib_mcast_iter_init(struct net_device *dev)
                return NULL;
 
        iter->dev = dev;
-       memset(iter->mgid.raw, 0, sizeof iter->mgid);
+       memset(iter->mgid.raw, 0, 16);
 
        if (ipoib_mcast_iter_next(iter)) {
-               ipoib_mcast_iter_free(iter);
+               kfree(iter);
                return NULL;
        }
 
        return iter;
 }
 
-void ipoib_mcast_iter_free(struct ipoib_mcast_iter *iter)
-{
-       kfree(iter);
-}
-
 int ipoib_mcast_iter_next(struct ipoib_mcast_iter *iter)
 {
        struct ipoib_dev_priv *priv = netdev_priv(iter->dev);
This page took 0.029791 seconds and 5 git commands to generate.