diff options
author | Michael S. Tsirkin <mst@mellanox.co.il> | 2006-03-02 14:07:47 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2006-03-20 13:08:20 -0500 |
commit | 9acf6a8570dcfc9f55724b8b71099fc8768e8c26 (patch) | |
tree | 5b265bf0474f321722d2690b5b5dc57cde80690e /drivers/infiniband/ulp | |
parent | 54d07e2a1ead2f093ce054cda2e0f5ec163c650c (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/ulp')
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 15 |
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; |