aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Cohen <eli@mellanox.co.il>2006-04-05 07:59:40 -0400
committerRoland Dreier <rolandd@cisco.com>2006-04-10 12:43:58 -0400
commitf2de3b06126ddb07d0e4617225d74dce0855add3 (patch)
tree21a62b2115804688d700c01ed2ede87413b5d9d1
parentbf6a9e31cfa768ce0a8e18474b3ca808641d9243 (diff)
IPoIB: Wait for join to finish before freeing mcast struct
ipoib_mcast_restart_task() might free an mcast object while a join request is still outstanding, leading to an oops when the query completes. Fix this by waiting for query to complete, similar to what ipoib_stop_thread() is doing. The wait for mcast completion code is consolidated in wait_for_mcast_join(). Signed-off-by: Eli Cohen <eli@mellanox.co.il> Signed-off-by: Roland Dreier <rolandd@cisco.com>
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c41
1 files changed, 20 insertions, 21 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index 07b9826b5193..1dae4b238252 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -609,6 +609,22 @@ int ipoib_mcast_start_thread(struct net_device *dev)
609 return 0; 609 return 0;
610} 610}
611 611
612static void wait_for_mcast_join(struct ipoib_dev_priv *priv,
613 struct ipoib_mcast *mcast)
614{
615 spin_lock_irq(&priv->lock);
616 if (mcast && mcast->query) {
617 ib_sa_cancel_query(mcast->query_id, mcast->query);
618 mcast->query = NULL;
619 spin_unlock_irq(&priv->lock);
620 ipoib_dbg_mcast(priv, "waiting for MGID " IPOIB_GID_FMT "\n",
621 IPOIB_GID_ARG(mcast->mcmember.mgid));
622 wait_for_completion(&mcast->done);
623 }
624 else
625 spin_unlock_irq(&priv->lock);
626}
627
612int ipoib_mcast_stop_thread(struct net_device *dev, int flush) 628int ipoib_mcast_stop_thread(struct net_device *dev, int flush)
613{ 629{
614 struct ipoib_dev_priv *priv = netdev_priv(dev); 630 struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -628,28 +644,10 @@ int ipoib_mcast_stop_thread(struct net_device *dev, int flush)
628 if (flush) 644 if (flush)
629 flush_workqueue(ipoib_workqueue); 645 flush_workqueue(ipoib_workqueue);
630 646
631 spin_lock_irq(&priv->lock); 647 wait_for_mcast_join(priv, priv->broadcast);
632 if (priv->broadcast && priv->broadcast->query) {
633 ib_sa_cancel_query(priv->broadcast->query_id, priv->broadcast->query);
634 priv->broadcast->query = NULL;
635 spin_unlock_irq(&priv->lock);
636 ipoib_dbg_mcast(priv, "waiting for bcast\n");
637 wait_for_completion(&priv->broadcast->done);
638 } else
639 spin_unlock_irq(&priv->lock);
640 648
641 list_for_each_entry(mcast, &priv->multicast_list, list) { 649 list_for_each_entry(mcast, &priv->multicast_list, list)
642 spin_lock_irq(&priv->lock); 650 wait_for_mcast_join(priv, mcast);
643 if (mcast->query) {
644 ib_sa_cancel_query(mcast->query_id, mcast->query);
645 mcast->query = NULL;
646 spin_unlock_irq(&priv->lock);
647 ipoib_dbg_mcast(priv, "waiting for MGID " IPOIB_GID_FMT "\n",
648 IPOIB_GID_ARG(mcast->mcmember.mgid));
649 wait_for_completion(&mcast->done);
650 } else
651 spin_unlock_irq(&priv->lock);
652 }
653 651
654 return 0; 652 return 0;
655} 653}
@@ -902,6 +900,7 @@ void ipoib_mcast_restart_task(void *dev_ptr)
902 900
903 /* We have to cancel outside of the spinlock */ 901 /* We have to cancel outside of the spinlock */
904 list_for_each_entry_safe(mcast, tmcast, &remove_list, list) { 902 list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
903 wait_for_mcast_join(priv, mcast);
905 ipoib_mcast_leave(mcast->dev, mcast); 904 ipoib_mcast_leave(mcast->dev, mcast);
906 ipoib_mcast_free(mcast); 905 ipoib_mcast_free(mcast);
907 } 906 }