aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@mellanox.co.il>2006-03-02 14:07:47 -0500
committerRoland Dreier <rolandd@cisco.com>2006-03-20 13:08:20 -0500
commit9acf6a8570dcfc9f55724b8b71099fc8768e8c26 (patch)
tree5b265bf0474f321722d2690b5b5dc57cde80690e /drivers/infiniband
parent54d07e2a1ead2f093ce054cda2e0f5ec163c650c (diff)
IPoIB: Fix multicast race between canceling and completing
ipoib_mcast_stop_thread currently tests mcast->query and if it is NULL, does not perform wait_for_completion on the mcast and frees the mcast object directly. However, since both operations are done without locking, it is possible that ipoib_mcast_join_complete is in progress on this mcast object and has set mcast->query to NULL already. Solve this by: - taking priv->lock before we change mcast->query in ipoib_mcast_join_complete, and keeping it until we no longer need the mcast object - taking priv->lock around mcast->query test in ipoib_mcast_stop_thread Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index e5dc2a034530..fde442a1996d 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -437,9 +437,11 @@ static void ipoib_mcast_join_complete(int status,
437 if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS) 437 if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)
438 mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS; 438 mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS;
439 439
440 mutex_lock(&mcast_mutex);
441
442 spin_lock_irq(&priv->lock);
440 mcast->query = NULL; 443 mcast->query = NULL;
441 444
442 mutex_lock(&mcast_mutex);
443 if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) { 445 if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) {
444 if (status == -ETIMEDOUT) 446 if (status == -ETIMEDOUT)
445 queue_work(ipoib_workqueue, &priv->mcast_task); 447 queue_work(ipoib_workqueue, &priv->mcast_task);
@@ -448,6 +450,7 @@ static void ipoib_mcast_join_complete(int status,
448 mcast->backoff * HZ); 450 mcast->backoff * HZ);
449 } else 451 } else
450 complete(&mcast->done); 452 complete(&mcast->done);
453 spin_unlock_irq(&priv->lock);
451 mutex_unlock(&mcast_mutex); 454 mutex_unlock(&mcast_mutex);
452 455
453 return; 456 return;
@@ -635,21 +638,27 @@ int ipoib_mcast_stop_thread(struct net_device *dev, int flush)
635 if (flush) 638 if (flush)
636 flush_workqueue(ipoib_workqueue); 639 flush_workqueue(ipoib_workqueue);
637 640
641 spin_lock_irq(&priv->lock);
638 if (priv->broadcast && priv->broadcast->query) { 642 if (priv->broadcast && priv->broadcast->query) {
639 ib_sa_cancel_query(priv->broadcast->query_id, priv->broadcast->query); 643 ib_sa_cancel_query(priv->broadcast->query_id, priv->broadcast->query);
640 priv->broadcast->query = NULL; 644 priv->broadcast->query = NULL;
645 spin_unlock_irq(&priv->lock);
641 ipoib_dbg_mcast(priv, "waiting for bcast\n"); 646 ipoib_dbg_mcast(priv, "waiting for bcast\n");
642 wait_for_completion(&priv->broadcast->done); 647 wait_for_completion(&priv->broadcast->done);
643 } 648 } else
649 spin_unlock_irq(&priv->lock);
644 650
645 list_for_each_entry(mcast, &priv->multicast_list, list) { 651 list_for_each_entry(mcast, &priv->multicast_list, list) {
652 spin_lock_irq(&priv->lock);
646 if (mcast->query) { 653 if (mcast->query) {
647 ib_sa_cancel_query(mcast->query_id, mcast->query); 654 ib_sa_cancel_query(mcast->query_id, mcast->query);
648 mcast->query = NULL; 655 mcast->query = NULL;
656 spin_unlock_irq(&priv->lock);
649 ipoib_dbg_mcast(priv, "waiting for MGID " IPOIB_GID_FMT "\n", 657 ipoib_dbg_mcast(priv, "waiting for MGID " IPOIB_GID_FMT "\n",
650 IPOIB_GID_ARG(mcast->mcmember.mgid)); 658 IPOIB_GID_ARG(mcast->mcmember.mgid));
651 wait_for_completion(&mcast->done); 659 wait_for_completion(&mcast->done);
652 } 660 } else
661 spin_unlock_irq(&priv->lock);
653 } 662 }
654 663
655 return 0; 664 return 0;