aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/ulp
diff options
context:
space:
mode:
authorErez Shitrit <erezsh@mellanox.com>2013-10-16 10:37:51 -0400
committerRoland Dreier <roland@purestorage.com>2013-11-08 17:42:49 -0500
commita9c8ba588495547d1598f1b83d5eb086bef65e4b (patch)
tree889eeb5b6597be549fe98f59f6384313b5f4a3e5 /drivers/infiniband/ulp
parentaede25011fddf559dcf216d86975187e3f64b109 (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.h2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c21
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
156struct ipoib_rx_buf { 158struct 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 440out:
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);