diff options
author | Erez Shitrit <erezsh@mellanox.com> | 2013-10-16 10:37:51 -0400 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2013-11-08 17:42:49 -0500 |
commit | a9c8ba588495547d1598f1b83d5eb086bef65e4b (patch) | |
tree | 889eeb5b6597be549fe98f59f6384313b5f4a3e5 /drivers/infiniband/ulp | |
parent | aede25011fddf559dcf216d86975187e3f64b109 (diff) |
IPoIB: Fix usage of uninitialized multicast objects
The driver should avoid calling ib_sa_free_multicast on the mcast->mc
object until it finishes its initialization state. Otherwise we can
crash when ipoib_mcast_dev_flush() attempts to use the uninitialized
multicast object.
Instead, only call wait_for_completion() for multicast entries that
started the join process, meaning that ib_sa_join_multicast() finished.
Signed-off-by: Erez Shitrit <erezsh@mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband/ulp')
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib.h | 2 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 21 |
2 files changed, 19 insertions, 4 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index ec9190eff09c..c639f90cfda4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h | |||
@@ -101,6 +101,7 @@ enum { | |||
101 | IPOIB_MCAST_FLAG_SENDONLY = 1, | 101 | IPOIB_MCAST_FLAG_SENDONLY = 1, |
102 | IPOIB_MCAST_FLAG_BUSY = 2, /* joining or already joined */ | 102 | IPOIB_MCAST_FLAG_BUSY = 2, /* joining or already joined */ |
103 | IPOIB_MCAST_FLAG_ATTACHED = 3, | 103 | IPOIB_MCAST_FLAG_ATTACHED = 3, |
104 | IPOIB_MCAST_JOIN_STARTED = 4, | ||
104 | 105 | ||
105 | MAX_SEND_CQE = 16, | 106 | MAX_SEND_CQE = 16, |
106 | IPOIB_CM_COPYBREAK = 256, | 107 | IPOIB_CM_COPYBREAK = 256, |
@@ -151,6 +152,7 @@ struct ipoib_mcast { | |||
151 | struct sk_buff_head pkt_queue; | 152 | struct sk_buff_head pkt_queue; |
152 | 153 | ||
153 | struct net_device *dev; | 154 | struct net_device *dev; |
155 | struct completion done; | ||
154 | }; | 156 | }; |
155 | 157 | ||
156 | struct ipoib_rx_buf { | 158 | struct ipoib_rx_buf { |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index cecb98a4c662..780a2a0df41f 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c | |||
@@ -386,8 +386,10 @@ static int ipoib_mcast_join_complete(int status, | |||
386 | mcast->mcmember.mgid.raw, status); | 386 | mcast->mcmember.mgid.raw, status); |
387 | 387 | ||
388 | /* We trap for port events ourselves. */ | 388 | /* We trap for port events ourselves. */ |
389 | if (status == -ENETRESET) | 389 | if (status == -ENETRESET) { |
390 | return 0; | 390 | status = 0; |
391 | goto out; | ||
392 | } | ||
391 | 393 | ||
392 | if (!status) | 394 | if (!status) |
393 | status = ipoib_mcast_join_finish(mcast, &multicast->rec); | 395 | status = ipoib_mcast_join_finish(mcast, &multicast->rec); |
@@ -407,7 +409,8 @@ static int ipoib_mcast_join_complete(int status, | |||
407 | if (mcast == priv->broadcast) | 409 | if (mcast == priv->broadcast) |
408 | queue_work(ipoib_workqueue, &priv->carrier_on_task); | 410 | queue_work(ipoib_workqueue, &priv->carrier_on_task); |
409 | 411 | ||
410 | return 0; | 412 | status = 0; |
413 | goto out; | ||
411 | } | 414 | } |
412 | 415 | ||
413 | if (mcast->logcount++ < 20) { | 416 | if (mcast->logcount++ < 20) { |
@@ -434,7 +437,8 @@ static int ipoib_mcast_join_complete(int status, | |||
434 | mcast->backoff * HZ); | 437 | mcast->backoff * HZ); |
435 | spin_unlock_irq(&priv->lock); | 438 | spin_unlock_irq(&priv->lock); |
436 | mutex_unlock(&mcast_mutex); | 439 | mutex_unlock(&mcast_mutex); |
437 | 440 | out: | |
441 | complete(&mcast->done); | ||
438 | return status; | 442 | return status; |
439 | } | 443 | } |
440 | 444 | ||
@@ -484,11 +488,15 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, | |||
484 | } | 488 | } |
485 | 489 | ||
486 | set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); | 490 | set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); |
491 | init_completion(&mcast->done); | ||
492 | set_bit(IPOIB_MCAST_JOIN_STARTED, &mcast->flags); | ||
493 | |||
487 | mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port, | 494 | mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port, |
488 | &rec, comp_mask, GFP_KERNEL, | 495 | &rec, comp_mask, GFP_KERNEL, |
489 | ipoib_mcast_join_complete, mcast); | 496 | ipoib_mcast_join_complete, mcast); |
490 | if (IS_ERR(mcast->mc)) { | 497 | if (IS_ERR(mcast->mc)) { |
491 | clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); | 498 | clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); |
499 | complete(&mcast->done); | ||
492 | ret = PTR_ERR(mcast->mc); | 500 | ret = PTR_ERR(mcast->mc); |
493 | ipoib_warn(priv, "ib_sa_join_multicast failed, status %d\n", ret); | 501 | ipoib_warn(priv, "ib_sa_join_multicast failed, status %d\n", ret); |
494 | 502 | ||
@@ -751,6 +759,11 @@ void ipoib_mcast_dev_flush(struct net_device *dev) | |||
751 | 759 | ||
752 | spin_unlock_irqrestore(&priv->lock, flags); | 760 | spin_unlock_irqrestore(&priv->lock, flags); |
753 | 761 | ||
762 | /* seperate between the wait to the leave*/ | ||
763 | list_for_each_entry_safe(mcast, tmcast, &remove_list, list) | ||
764 | if (test_bit(IPOIB_MCAST_JOIN_STARTED, &mcast->flags)) | ||
765 | wait_for_completion(&mcast->done); | ||
766 | |||
754 | list_for_each_entry_safe(mcast, tmcast, &remove_list, list) { | 767 | list_for_each_entry_safe(mcast, tmcast, &remove_list, list) { |
755 | ipoib_mcast_leave(dev, mcast); | 768 | ipoib_mcast_leave(dev, mcast); |
756 | ipoib_mcast_free(mcast); | 769 | ipoib_mcast_free(mcast); |