diff options
| author | Sean Hefty <mshefty@ichips.intel.com> | 2006-05-12 17:57:52 -0400 | 
|---|---|---|
| committer | Roland Dreier <rolandd@cisco.com> | 2006-05-12 17:57:52 -0400 | 
| commit | 1b52fa98edd1c3e663ea4a06519e3d20976084a8 (patch) | |
| tree | 178d5fd1fe2230b39f49cd36f481024e49878eb1 | |
| parent | 6f4bb3d8205d943acafa2f536f37131777524b67 (diff) | |
IB: refcount race fixes
Fix race condition during destruction calls to avoid possibility of
accessing object after it has been freed.  Instead of waking up a wait
queue directly, which is susceptible to a race where the object is
freed between the reference count going to 0 and the wake_up(), use a
completion to wait in the function doing the freeing.
Signed-off-by: Sean Hefty <sean.hefty@intel.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
| -rw-r--r-- | drivers/infiniband/core/cm.c | 12 | ||||
| -rw-r--r-- | drivers/infiniband/core/mad.c | 47 | ||||
| -rw-r--r-- | drivers/infiniband/core/mad_priv.h | 5 | ||||
| -rw-r--r-- | drivers/infiniband/core/mad_rmpp.c | 20 | ||||
| -rw-r--r-- | drivers/infiniband/core/ucm.c | 12 | 
5 files changed, 52 insertions, 44 deletions
| diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 7cfedb8d9bcd..86fee43502cd 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c | |||
| @@ -34,6 +34,8 @@ | |||
| 34 | * | 34 | * | 
| 35 | * $Id: cm.c 2821 2005-07-08 17:07:28Z sean.hefty $ | 35 | * $Id: cm.c 2821 2005-07-08 17:07:28Z sean.hefty $ | 
| 36 | */ | 36 | */ | 
| 37 | |||
| 38 | #include <linux/completion.h> | ||
| 37 | #include <linux/dma-mapping.h> | 39 | #include <linux/dma-mapping.h> | 
| 38 | #include <linux/err.h> | 40 | #include <linux/err.h> | 
| 39 | #include <linux/idr.h> | 41 | #include <linux/idr.h> | 
| @@ -122,7 +124,7 @@ struct cm_id_private { | |||
| 122 | struct rb_node service_node; | 124 | struct rb_node service_node; | 
| 123 | struct rb_node sidr_id_node; | 125 | struct rb_node sidr_id_node; | 
| 124 | spinlock_t lock; /* Do not acquire inside cm.lock */ | 126 | spinlock_t lock; /* Do not acquire inside cm.lock */ | 
| 125 | wait_queue_head_t wait; | 127 | struct completion comp; | 
| 126 | atomic_t refcount; | 128 | atomic_t refcount; | 
| 127 | 129 | ||
| 128 | struct ib_mad_send_buf *msg; | 130 | struct ib_mad_send_buf *msg; | 
| @@ -159,7 +161,7 @@ static void cm_work_handler(void *data); | |||
| 159 | static inline void cm_deref_id(struct cm_id_private *cm_id_priv) | 161 | static inline void cm_deref_id(struct cm_id_private *cm_id_priv) | 
| 160 | { | 162 | { | 
| 161 | if (atomic_dec_and_test(&cm_id_priv->refcount)) | 163 | if (atomic_dec_and_test(&cm_id_priv->refcount)) | 
| 162 | wake_up(&cm_id_priv->wait); | 164 | complete(&cm_id_priv->comp); | 
| 163 | } | 165 | } | 
| 164 | 166 | ||
| 165 | static int cm_alloc_msg(struct cm_id_private *cm_id_priv, | 167 | static int cm_alloc_msg(struct cm_id_private *cm_id_priv, | 
| @@ -559,7 +561,7 @@ struct ib_cm_id *ib_create_cm_id(struct ib_device *device, | |||
| 559 | goto error; | 561 | goto error; | 
| 560 | 562 | ||
| 561 | spin_lock_init(&cm_id_priv->lock); | 563 | spin_lock_init(&cm_id_priv->lock); | 
| 562 | init_waitqueue_head(&cm_id_priv->wait); | 564 | init_completion(&cm_id_priv->comp); | 
| 563 | INIT_LIST_HEAD(&cm_id_priv->work_list); | 565 | INIT_LIST_HEAD(&cm_id_priv->work_list); | 
| 564 | atomic_set(&cm_id_priv->work_count, -1); | 566 | atomic_set(&cm_id_priv->work_count, -1); | 
| 565 | atomic_set(&cm_id_priv->refcount, 1); | 567 | atomic_set(&cm_id_priv->refcount, 1); | 
| @@ -724,8 +726,8 @@ retest: | |||
| 724 | } | 726 | } | 
| 725 | 727 | ||
| 726 | cm_free_id(cm_id->local_id); | 728 | cm_free_id(cm_id->local_id); | 
| 727 | atomic_dec(&cm_id_priv->refcount); | 729 | cm_deref_id(cm_id_priv); | 
| 728 | wait_event(cm_id_priv->wait, !atomic_read(&cm_id_priv->refcount)); | 730 | wait_for_completion(&cm_id_priv->comp); | 
| 729 | while ((work = cm_dequeue_work(cm_id_priv)) != NULL) | 731 | while ((work = cm_dequeue_work(cm_id_priv)) != NULL) | 
| 730 | cm_free_work(work); | 732 | cm_free_work(work); | 
| 731 | if (cm_id_priv->private_data && cm_id_priv->private_data_len) | 733 | if (cm_id_priv->private_data && cm_id_priv->private_data_len) | 
| diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 469b6923a2e2..5ad41a64314c 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c | |||
| @@ -352,7 +352,7 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, | |||
| 352 | INIT_WORK(&mad_agent_priv->local_work, local_completions, | 352 | INIT_WORK(&mad_agent_priv->local_work, local_completions, | 
| 353 | mad_agent_priv); | 353 | mad_agent_priv); | 
| 354 | atomic_set(&mad_agent_priv->refcount, 1); | 354 | atomic_set(&mad_agent_priv->refcount, 1); | 
| 355 | init_waitqueue_head(&mad_agent_priv->wait); | 355 | init_completion(&mad_agent_priv->comp); | 
| 356 | 356 | ||
| 357 | return &mad_agent_priv->agent; | 357 | return &mad_agent_priv->agent; | 
| 358 | 358 | ||
| @@ -467,7 +467,7 @@ struct ib_mad_agent *ib_register_mad_snoop(struct ib_device *device, | |||
| 467 | mad_snoop_priv->agent.qp = port_priv->qp_info[qpn].qp; | 467 | mad_snoop_priv->agent.qp = port_priv->qp_info[qpn].qp; | 
| 468 | mad_snoop_priv->agent.port_num = port_num; | 468 | mad_snoop_priv->agent.port_num = port_num; | 
| 469 | mad_snoop_priv->mad_snoop_flags = mad_snoop_flags; | 469 | mad_snoop_priv->mad_snoop_flags = mad_snoop_flags; | 
| 470 | init_waitqueue_head(&mad_snoop_priv->wait); | 470 | init_completion(&mad_snoop_priv->comp); | 
| 471 | mad_snoop_priv->snoop_index = register_snoop_agent( | 471 | mad_snoop_priv->snoop_index = register_snoop_agent( | 
| 472 | &port_priv->qp_info[qpn], | 472 | &port_priv->qp_info[qpn], | 
| 473 | mad_snoop_priv); | 473 | mad_snoop_priv); | 
| @@ -486,6 +486,18 @@ error1: | |||
| 486 | } | 486 | } | 
| 487 | EXPORT_SYMBOL(ib_register_mad_snoop); | 487 | EXPORT_SYMBOL(ib_register_mad_snoop); | 
| 488 | 488 | ||
| 489 | static inline void deref_mad_agent(struct ib_mad_agent_private *mad_agent_priv) | ||
| 490 | { | ||
| 491 | if (atomic_dec_and_test(&mad_agent_priv->refcount)) | ||
| 492 | complete(&mad_agent_priv->comp); | ||
| 493 | } | ||
| 494 | |||
| 495 | static inline void deref_snoop_agent(struct ib_mad_snoop_private *mad_snoop_priv) | ||
| 496 | { | ||
| 497 | if (atomic_dec_and_test(&mad_snoop_priv->refcount)) | ||
| 498 | complete(&mad_snoop_priv->comp); | ||
| 499 | } | ||
| 500 | |||
| 489 | static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv) | 501 | static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv) | 
| 490 | { | 502 | { | 
| 491 | struct ib_mad_port_private *port_priv; | 503 | struct ib_mad_port_private *port_priv; | 
| @@ -509,9 +521,8 @@ static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv) | |||
| 509 | flush_workqueue(port_priv->wq); | 521 | flush_workqueue(port_priv->wq); | 
| 510 | ib_cancel_rmpp_recvs(mad_agent_priv); | 522 | ib_cancel_rmpp_recvs(mad_agent_priv); | 
| 511 | 523 | ||
| 512 | atomic_dec(&mad_agent_priv->refcount); | 524 | deref_mad_agent(mad_agent_priv); | 
| 513 | wait_event(mad_agent_priv->wait, | 525 | wait_for_completion(&mad_agent_priv->comp); | 
| 514 | !atomic_read(&mad_agent_priv->refcount)); | ||
| 515 | 526 | ||
| 516 | kfree(mad_agent_priv->reg_req); | 527 | kfree(mad_agent_priv->reg_req); | 
| 517 | ib_dereg_mr(mad_agent_priv->agent.mr); | 528 | ib_dereg_mr(mad_agent_priv->agent.mr); | 
| @@ -529,9 +540,8 @@ static void unregister_mad_snoop(struct ib_mad_snoop_private *mad_snoop_priv) | |||
| 529 | atomic_dec(&qp_info->snoop_count); | 540 | atomic_dec(&qp_info->snoop_count); | 
| 530 | spin_unlock_irqrestore(&qp_info->snoop_lock, flags); | 541 | spin_unlock_irqrestore(&qp_info->snoop_lock, flags); | 
| 531 | 542 | ||
| 532 | atomic_dec(&mad_snoop_priv->refcount); | 543 | deref_snoop_agent(mad_snoop_priv); | 
| 533 | wait_event(mad_snoop_priv->wait, | 544 | wait_for_completion(&mad_snoop_priv->comp); | 
| 534 | !atomic_read(&mad_snoop_priv->refcount)); | ||
| 535 | 545 | ||
| 536 | kfree(mad_snoop_priv); | 546 | kfree(mad_snoop_priv); | 
| 537 | } | 547 | } | 
| @@ -600,8 +610,7 @@ static void snoop_send(struct ib_mad_qp_info *qp_info, | |||
| 600 | spin_unlock_irqrestore(&qp_info->snoop_lock, flags); | 610 | spin_unlock_irqrestore(&qp_info->snoop_lock, flags); | 
| 601 | mad_snoop_priv->agent.snoop_handler(&mad_snoop_priv->agent, | 611 | mad_snoop_priv->agent.snoop_handler(&mad_snoop_priv->agent, | 
| 602 | send_buf, mad_send_wc); | 612 | send_buf, mad_send_wc); | 
| 603 | if (atomic_dec_and_test(&mad_snoop_priv->refcount)) | 613 | deref_snoop_agent(mad_snoop_priv); | 
| 604 | wake_up(&mad_snoop_priv->wait); | ||
| 605 | spin_lock_irqsave(&qp_info->snoop_lock, flags); | 614 | spin_lock_irqsave(&qp_info->snoop_lock, flags); | 
| 606 | } | 615 | } | 
| 607 | spin_unlock_irqrestore(&qp_info->snoop_lock, flags); | 616 | spin_unlock_irqrestore(&qp_info->snoop_lock, flags); | 
| @@ -626,8 +635,7 @@ static void snoop_recv(struct ib_mad_qp_info *qp_info, | |||
| 626 | spin_unlock_irqrestore(&qp_info->snoop_lock, flags); | 635 | spin_unlock_irqrestore(&qp_info->snoop_lock, flags); | 
| 627 | mad_snoop_priv->agent.recv_handler(&mad_snoop_priv->agent, | 636 | mad_snoop_priv->agent.recv_handler(&mad_snoop_priv->agent, | 
| 628 | mad_recv_wc); | 637 | mad_recv_wc); | 
| 629 | if (atomic_dec_and_test(&mad_snoop_priv->refcount)) | 638 | deref_snoop_agent(mad_snoop_priv); | 
| 630 | wake_up(&mad_snoop_priv->wait); | ||
| 631 | spin_lock_irqsave(&qp_info->snoop_lock, flags); | 639 | spin_lock_irqsave(&qp_info->snoop_lock, flags); | 
| 632 | } | 640 | } | 
| 633 | spin_unlock_irqrestore(&qp_info->snoop_lock, flags); | 641 | spin_unlock_irqrestore(&qp_info->snoop_lock, flags); | 
| @@ -968,8 +976,7 @@ void ib_free_send_mad(struct ib_mad_send_buf *send_buf) | |||
| 968 | 976 | ||
| 969 | free_send_rmpp_list(mad_send_wr); | 977 | free_send_rmpp_list(mad_send_wr); | 
| 970 | kfree(send_buf->mad); | 978 | kfree(send_buf->mad); | 
| 971 | if (atomic_dec_and_test(&mad_agent_priv->refcount)) | 979 | deref_mad_agent(mad_agent_priv); | 
| 972 | wake_up(&mad_agent_priv->wait); | ||
| 973 | } | 980 | } | 
| 974 | EXPORT_SYMBOL(ib_free_send_mad); | 981 | EXPORT_SYMBOL(ib_free_send_mad); | 
| 975 | 982 | ||
| @@ -1757,8 +1764,7 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, | |||
| 1757 | mad_recv_wc = ib_process_rmpp_recv_wc(mad_agent_priv, | 1764 | mad_recv_wc = ib_process_rmpp_recv_wc(mad_agent_priv, | 
| 1758 | mad_recv_wc); | 1765 | mad_recv_wc); | 
| 1759 | if (!mad_recv_wc) { | 1766 | if (!mad_recv_wc) { | 
| 1760 | if (atomic_dec_and_test(&mad_agent_priv->refcount)) | 1767 | deref_mad_agent(mad_agent_priv); | 
| 1761 | wake_up(&mad_agent_priv->wait); | ||
| 1762 | return; | 1768 | return; | 
| 1763 | } | 1769 | } | 
| 1764 | } | 1770 | } | 
| @@ -1770,8 +1776,7 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, | |||
| 1770 | if (!mad_send_wr) { | 1776 | if (!mad_send_wr) { | 
| 1771 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | 1777 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | 
| 1772 | ib_free_recv_mad(mad_recv_wc); | 1778 | ib_free_recv_mad(mad_recv_wc); | 
| 1773 | if (atomic_dec_and_test(&mad_agent_priv->refcount)) | 1779 | deref_mad_agent(mad_agent_priv); | 
| 1774 | wake_up(&mad_agent_priv->wait); | ||
| 1775 | return; | 1780 | return; | 
| 1776 | } | 1781 | } | 
| 1777 | ib_mark_mad_done(mad_send_wr); | 1782 | ib_mark_mad_done(mad_send_wr); | 
| @@ -1790,8 +1795,7 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, | |||
| 1790 | } else { | 1795 | } else { | 
| 1791 | mad_agent_priv->agent.recv_handler(&mad_agent_priv->agent, | 1796 | mad_agent_priv->agent.recv_handler(&mad_agent_priv->agent, | 
| 1792 | mad_recv_wc); | 1797 | mad_recv_wc); | 
| 1793 | if (atomic_dec_and_test(&mad_agent_priv->refcount)) | 1798 | deref_mad_agent(mad_agent_priv); | 
| 1794 | wake_up(&mad_agent_priv->wait); | ||
| 1795 | } | 1799 | } | 
| 1796 | } | 1800 | } | 
| 1797 | 1801 | ||
| @@ -2021,8 +2025,7 @@ void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr, | |||
| 2021 | mad_send_wc); | 2025 | mad_send_wc); | 
| 2022 | 2026 | ||
| 2023 | /* Release reference on agent taken when sending */ | 2027 | /* Release reference on agent taken when sending */ | 
| 2024 | if (atomic_dec_and_test(&mad_agent_priv->refcount)) | 2028 | deref_mad_agent(mad_agent_priv); | 
| 2025 | wake_up(&mad_agent_priv->wait); | ||
| 2026 | return; | 2029 | return; | 
| 2027 | done: | 2030 | done: | 
| 2028 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | 2031 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | 
| diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h index 6c9c133d71ef..b4fa28d3160f 100644 --- a/drivers/infiniband/core/mad_priv.h +++ b/drivers/infiniband/core/mad_priv.h | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #ifndef __IB_MAD_PRIV_H__ | 37 | #ifndef __IB_MAD_PRIV_H__ | 
| 38 | #define __IB_MAD_PRIV_H__ | 38 | #define __IB_MAD_PRIV_H__ | 
| 39 | 39 | ||
| 40 | #include <linux/completion.h> | ||
| 40 | #include <linux/pci.h> | 41 | #include <linux/pci.h> | 
| 41 | #include <linux/kthread.h> | 42 | #include <linux/kthread.h> | 
| 42 | #include <linux/workqueue.h> | 43 | #include <linux/workqueue.h> | 
| @@ -108,7 +109,7 @@ struct ib_mad_agent_private { | |||
| 108 | struct list_head rmpp_list; | 109 | struct list_head rmpp_list; | 
| 109 | 110 | ||
| 110 | atomic_t refcount; | 111 | atomic_t refcount; | 
| 111 | wait_queue_head_t wait; | 112 | struct completion comp; | 
| 112 | }; | 113 | }; | 
| 113 | 114 | ||
| 114 | struct ib_mad_snoop_private { | 115 | struct ib_mad_snoop_private { | 
| @@ -117,7 +118,7 @@ struct ib_mad_snoop_private { | |||
| 117 | int snoop_index; | 118 | int snoop_index; | 
| 118 | int mad_snoop_flags; | 119 | int mad_snoop_flags; | 
| 119 | atomic_t refcount; | 120 | atomic_t refcount; | 
| 120 | wait_queue_head_t wait; | 121 | struct completion comp; | 
| 121 | }; | 122 | }; | 
| 122 | 123 | ||
| 123 | struct ib_mad_send_wr_private { | 124 | struct ib_mad_send_wr_private { | 
| diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c index dfd4e588ce03..d4704e054e30 100644 --- a/drivers/infiniband/core/mad_rmpp.c +++ b/drivers/infiniband/core/mad_rmpp.c | |||
| @@ -49,7 +49,7 @@ struct mad_rmpp_recv { | |||
| 49 | struct list_head list; | 49 | struct list_head list; | 
| 50 | struct work_struct timeout_work; | 50 | struct work_struct timeout_work; | 
| 51 | struct work_struct cleanup_work; | 51 | struct work_struct cleanup_work; | 
| 52 | wait_queue_head_t wait; | 52 | struct completion comp; | 
| 53 | enum rmpp_state state; | 53 | enum rmpp_state state; | 
| 54 | spinlock_t lock; | 54 | spinlock_t lock; | 
| 55 | atomic_t refcount; | 55 | atomic_t refcount; | 
| @@ -69,10 +69,16 @@ struct mad_rmpp_recv { | |||
| 69 | u8 method; | 69 | u8 method; | 
| 70 | }; | 70 | }; | 
| 71 | 71 | ||
| 72 | static inline void deref_rmpp_recv(struct mad_rmpp_recv *rmpp_recv) | ||
| 73 | { | ||
| 74 | if (atomic_dec_and_test(&rmpp_recv->refcount)) | ||
| 75 | complete(&rmpp_recv->comp); | ||
| 76 | } | ||
| 77 | |||
| 72 | static void destroy_rmpp_recv(struct mad_rmpp_recv *rmpp_recv) | 78 | static void destroy_rmpp_recv(struct mad_rmpp_recv *rmpp_recv) | 
| 73 | { | 79 | { | 
| 74 | atomic_dec(&rmpp_recv->refcount); | 80 | deref_rmpp_recv(rmpp_recv); | 
| 75 | wait_event(rmpp_recv->wait, !atomic_read(&rmpp_recv->refcount)); | 81 | wait_for_completion(&rmpp_recv->comp); | 
| 76 | ib_destroy_ah(rmpp_recv->ah); | 82 | ib_destroy_ah(rmpp_recv->ah); | 
| 77 | kfree(rmpp_recv); | 83 | kfree(rmpp_recv); | 
| 78 | } | 84 | } | 
| @@ -253,7 +259,7 @@ create_rmpp_recv(struct ib_mad_agent_private *agent, | |||
| 253 | goto error; | 259 | goto error; | 
| 254 | 260 | ||
| 255 | rmpp_recv->agent = agent; | 261 | rmpp_recv->agent = agent; | 
| 256 | init_waitqueue_head(&rmpp_recv->wait); | 262 | init_completion(&rmpp_recv->comp); | 
| 257 | INIT_WORK(&rmpp_recv->timeout_work, recv_timeout_handler, rmpp_recv); | 263 | INIT_WORK(&rmpp_recv->timeout_work, recv_timeout_handler, rmpp_recv); | 
| 258 | INIT_WORK(&rmpp_recv->cleanup_work, recv_cleanup_handler, rmpp_recv); | 264 | INIT_WORK(&rmpp_recv->cleanup_work, recv_cleanup_handler, rmpp_recv); | 
| 259 | spin_lock_init(&rmpp_recv->lock); | 265 | spin_lock_init(&rmpp_recv->lock); | 
| @@ -279,12 +285,6 @@ error: kfree(rmpp_recv); | |||
| 279 | return NULL; | 285 | return NULL; | 
| 280 | } | 286 | } | 
| 281 | 287 | ||
| 282 | static inline void deref_rmpp_recv(struct mad_rmpp_recv *rmpp_recv) | ||
| 283 | { | ||
| 284 | if (atomic_dec_and_test(&rmpp_recv->refcount)) | ||
| 285 | wake_up(&rmpp_recv->wait); | ||
| 286 | } | ||
| 287 | |||
| 288 | static struct mad_rmpp_recv * | 288 | static struct mad_rmpp_recv * | 
| 289 | find_rmpp_recv(struct ib_mad_agent_private *agent, | 289 | find_rmpp_recv(struct ib_mad_agent_private *agent, | 
| 290 | struct ib_mad_recv_wc *mad_recv_wc) | 290 | struct ib_mad_recv_wc *mad_recv_wc) | 
| diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index f6a05965a4e8..9164a09b6ccd 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c | |||
| @@ -32,6 +32,8 @@ | |||
| 32 | * | 32 | * | 
| 33 | * $Id: ucm.c 2594 2005-06-13 19:46:02Z libor $ | 33 | * $Id: ucm.c 2594 2005-06-13 19:46:02Z libor $ | 
| 34 | */ | 34 | */ | 
| 35 | |||
| 36 | #include <linux/completion.h> | ||
| 35 | #include <linux/init.h> | 37 | #include <linux/init.h> | 
| 36 | #include <linux/fs.h> | 38 | #include <linux/fs.h> | 
| 37 | #include <linux/module.h> | 39 | #include <linux/module.h> | 
| @@ -72,7 +74,7 @@ struct ib_ucm_file { | |||
| 72 | 74 | ||
| 73 | struct ib_ucm_context { | 75 | struct ib_ucm_context { | 
| 74 | int id; | 76 | int id; | 
| 75 | wait_queue_head_t wait; | 77 | struct completion comp; | 
| 76 | atomic_t ref; | 78 | atomic_t ref; | 
| 77 | int events_reported; | 79 | int events_reported; | 
| 78 | 80 | ||
| @@ -138,7 +140,7 @@ static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id) | |||
| 138 | static void ib_ucm_ctx_put(struct ib_ucm_context *ctx) | 140 | static void ib_ucm_ctx_put(struct ib_ucm_context *ctx) | 
| 139 | { | 141 | { | 
| 140 | if (atomic_dec_and_test(&ctx->ref)) | 142 | if (atomic_dec_and_test(&ctx->ref)) | 
| 141 | wake_up(&ctx->wait); | 143 | complete(&ctx->comp); | 
| 142 | } | 144 | } | 
| 143 | 145 | ||
| 144 | static inline int ib_ucm_new_cm_id(int event) | 146 | static inline int ib_ucm_new_cm_id(int event) | 
| @@ -178,7 +180,7 @@ static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file) | |||
| 178 | return NULL; | 180 | return NULL; | 
| 179 | 181 | ||
| 180 | atomic_set(&ctx->ref, 1); | 182 | atomic_set(&ctx->ref, 1); | 
| 181 | init_waitqueue_head(&ctx->wait); | 183 | init_completion(&ctx->comp); | 
| 182 | ctx->file = file; | 184 | ctx->file = file; | 
| 183 | INIT_LIST_HEAD(&ctx->events); | 185 | INIT_LIST_HEAD(&ctx->events); | 
| 184 | 186 | ||
| @@ -586,8 +588,8 @@ static ssize_t ib_ucm_destroy_id(struct ib_ucm_file *file, | |||
| 586 | if (IS_ERR(ctx)) | 588 | if (IS_ERR(ctx)) | 
| 587 | return PTR_ERR(ctx); | 589 | return PTR_ERR(ctx); | 
| 588 | 590 | ||
| 589 | atomic_dec(&ctx->ref); | 591 | ib_ucm_ctx_put(ctx); | 
| 590 | wait_event(ctx->wait, !atomic_read(&ctx->ref)); | 592 | wait_for_completion(&ctx->comp); | 
| 591 | 593 | ||
| 592 | /* No new events will be generated after destroying the cm_id. */ | 594 | /* No new events will be generated after destroying the cm_id. */ | 
| 593 | ib_destroy_cm_id(ctx->cm_id); | 595 | ib_destroy_cm_id(ctx->cm_id); | 
