diff options
Diffstat (limited to 'drivers/infiniband/ulp/ipoib/ipoib_multicast.c')
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 105 |
1 files changed, 33 insertions, 72 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index ed0c2ea..98039da 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -55,7 +55,7 @@ MODULE_PARM_DESC(mcast_debug_level, "Enable multicast debug tracing if > 0"); #endif -static DECLARE_MUTEX(mcast_mutex); +static DEFINE_MUTEX(mcast_mutex); /* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */ struct ipoib_mcast { @@ -97,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", @@ -107,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); @@ -116,9 +120,6 @@ 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); @@ -384,10 +385,10 @@ static void ipoib_mcast_join_complete(int status, if (!status && !ipoib_mcast_join_finish(mcast, mcmember)) { mcast->backoff = 1; - down(&mcast_mutex); + mutex_lock(&mcast_mutex); if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) queue_work(ipoib_workqueue, &priv->mcast_task); - up(&mcast_mutex); + mutex_unlock(&mcast_mutex); complete(&mcast->done); return; } @@ -417,7 +418,7 @@ static void ipoib_mcast_join_complete(int status, mcast->query = NULL; - down(&mcast_mutex); + mutex_lock(&mcast_mutex); if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) { if (status == -ETIMEDOUT) queue_work(ipoib_workqueue, &priv->mcast_task); @@ -426,7 +427,7 @@ static void ipoib_mcast_join_complete(int status, mcast->backoff * HZ); } else complete(&mcast->done); - up(&mcast_mutex); + mutex_unlock(&mcast_mutex); return; } @@ -481,12 +482,12 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS) mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS; - down(&mcast_mutex); + mutex_lock(&mcast_mutex); if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) queue_delayed_work(ipoib_workqueue, &priv->mcast_task, mcast->backoff * HZ); - up(&mcast_mutex); + mutex_unlock(&mcast_mutex); } else mcast->query_id = ret; } @@ -519,11 +520,11 @@ void ipoib_mcast_join_task(void *dev_ptr) priv->broadcast = ipoib_mcast_alloc(dev, 1); if (!priv->broadcast) { ipoib_warn(priv, "failed to allocate broadcast group\n"); - down(&mcast_mutex); + mutex_lock(&mcast_mutex); if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) queue_delayed_work(ipoib_workqueue, &priv->mcast_task, HZ); - up(&mcast_mutex); + mutex_unlock(&mcast_mutex); return; } @@ -579,10 +580,10 @@ int ipoib_mcast_start_thread(struct net_device *dev) ipoib_dbg_mcast(priv, "starting multicast thread\n"); - down(&mcast_mutex); + mutex_lock(&mcast_mutex); if (!test_and_set_bit(IPOIB_MCAST_RUN, &priv->flags)) queue_work(ipoib_workqueue, &priv->mcast_task); - up(&mcast_mutex); + mutex_unlock(&mcast_mutex); return 0; } @@ -594,10 +595,10 @@ int ipoib_mcast_stop_thread(struct net_device *dev, int flush) ipoib_dbg_mcast(priv, "stopping multicast thread\n"); - down(&mcast_mutex); + mutex_lock(&mcast_mutex); clear_bit(IPOIB_MCAST_RUN, &priv->flags); cancel_delayed_work(&priv->mcast_task); - up(&mcast_mutex); + mutex_unlock(&mcast_mutex); if (flush) flush_workqueue(ipoib_workqueue); @@ -741,48 +742,23 @@ void ipoib_mcast_dev_flush(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); LIST_HEAD(remove_list); - struct ipoib_mcast *mcast, *tmcast, *nmcast; + struct ipoib_mcast *mcast, *tmcast; unsigned long flags; ipoib_dbg_mcast(priv, "flushing multicast list\n"); spin_lock_irqsave(&priv->lock, flags); - list_for_each_entry_safe(mcast, tmcast, &priv->multicast_list, list) { - nmcast = ipoib_mcast_alloc(dev, 0); - if (nmcast) { - nmcast->flags = - mcast->flags & (1 << IPOIB_MCAST_FLAG_SENDONLY); - nmcast->mcmember.mgid = mcast->mcmember.mgid; - - /* Add the new group in before the to-be-destroyed group */ - list_add_tail(&nmcast->list, &mcast->list); - list_del_init(&mcast->list); - - rb_replace_node(&mcast->rb_node, &nmcast->rb_node, - &priv->multicast_tree); - - list_add_tail(&mcast->list, &remove_list); - } else { - ipoib_warn(priv, "could not reallocate multicast group " - IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); - } + list_for_each_entry_safe(mcast, tmcast, &priv->multicast_list, list) { + list_del(&mcast->list); + rb_erase(&mcast->rb_node, &priv->multicast_tree); + list_add_tail(&mcast->list, &remove_list); } if (priv->broadcast) { - nmcast = ipoib_mcast_alloc(dev, 0); - if (nmcast) { - nmcast->mcmember.mgid = priv->broadcast->mcmember.mgid; - - rb_replace_node(&priv->broadcast->rb_node, - &nmcast->rb_node, - &priv->multicast_tree); - - list_add_tail(&priv->broadcast->list, &remove_list); - } - - priv->broadcast = nmcast; + rb_erase(&priv->broadcast->rb_node, &priv->multicast_tree); + list_add_tail(&priv->broadcast->list, &remove_list); + priv->broadcast = NULL; } spin_unlock_irqrestore(&priv->lock, flags); @@ -793,24 +769,6 @@ void ipoib_mcast_dev_flush(struct net_device *dev) } } -void ipoib_mcast_dev_down(struct net_device *dev) -{ - struct ipoib_dev_priv *priv = netdev_priv(dev); - unsigned long flags; - - /* Delete broadcast since it will be recreated */ - if (priv->broadcast) { - ipoib_dbg_mcast(priv, "deleting broadcast group\n"); - - spin_lock_irqsave(&priv->lock, flags); - rb_erase(&priv->broadcast->rb_node, &priv->multicast_tree); - spin_unlock_irqrestore(&priv->lock, flags); - ipoib_mcast_leave(dev, priv->broadcast); - ipoib_mcast_free(priv->broadcast); - priv->broadcast = NULL; - } -} - void ipoib_mcast_restart_task(void *dev_ptr) { struct net_device *dev = dev_ptr; @@ -824,7 +782,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 @@ -896,7 +855,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) { |