aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@mellanox.co.il>2006-03-20 13:08:25 -0500
committerRoland Dreier <rolandd@cisco.com>2006-03-20 13:08:25 -0500
commitdc05980dd736bfbe5b2524b463e5f098e67a64e9 (patch)
tree87f212e24ee4362a5e670418b32bd0c959d3f1c6 /drivers/infiniband
parentbf17c1c7cc9250d7c3c01b0ae898aefa1853535a (diff)
IB/mad: Fix oopsable race on device removal
Fix an oopsable race debugged by Eli Cohen <eli@mellanox.co.il>: After removing the port from port_list, ib_mad_port_close flushes port_priv->wq before destroying the special QPs. This means that a completion event could arrive, and queue a new work in this work queue after flush. This patch also removes an unnecessary flush_workqueue(): destroy_workqueue() already includes a flush. 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/core/mad.c21
1 files changed, 14 insertions, 7 deletions
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 16549add8e8f..f7854b65fd55 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -2364,8 +2364,12 @@ static void timeout_sends(void *data)
2364static void ib_mad_thread_completion_handler(struct ib_cq *cq, void *arg) 2364static void ib_mad_thread_completion_handler(struct ib_cq *cq, void *arg)
2365{ 2365{
2366 struct ib_mad_port_private *port_priv = cq->cq_context; 2366 struct ib_mad_port_private *port_priv = cq->cq_context;
2367 unsigned long flags;
2367 2368
2368 queue_work(port_priv->wq, &port_priv->work); 2369 spin_lock_irqsave(&ib_mad_port_list_lock, flags);
2370 if (!list_empty(&port_priv->port_list))
2371 queue_work(port_priv->wq, &port_priv->work);
2372 spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
2369} 2373}
2370 2374
2371/* 2375/*
@@ -2677,18 +2681,23 @@ static int ib_mad_port_open(struct ib_device *device,
2677 } 2681 }
2678 INIT_WORK(&port_priv->work, ib_mad_completion_handler, port_priv); 2682 INIT_WORK(&port_priv->work, ib_mad_completion_handler, port_priv);
2679 2683
2684 spin_lock_irqsave(&ib_mad_port_list_lock, flags);
2685 list_add_tail(&port_priv->port_list, &ib_mad_port_list);
2686 spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
2687
2680 ret = ib_mad_port_start(port_priv); 2688 ret = ib_mad_port_start(port_priv);
2681 if (ret) { 2689 if (ret) {
2682 printk(KERN_ERR PFX "Couldn't start port\n"); 2690 printk(KERN_ERR PFX "Couldn't start port\n");
2683 goto error9; 2691 goto error9;
2684 } 2692 }
2685 2693
2686 spin_lock_irqsave(&ib_mad_port_list_lock, flags);
2687 list_add_tail(&port_priv->port_list, &ib_mad_port_list);
2688 spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
2689 return 0; 2694 return 0;
2690 2695
2691error9: 2696error9:
2697 spin_lock_irqsave(&ib_mad_port_list_lock, flags);
2698 list_del_init(&port_priv->port_list);
2699 spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
2700
2692 destroy_workqueue(port_priv->wq); 2701 destroy_workqueue(port_priv->wq);
2693error8: 2702error8:
2694 destroy_mad_qp(&port_priv->qp_info[1]); 2703 destroy_mad_qp(&port_priv->qp_info[1]);
@@ -2725,11 +2734,9 @@ static int ib_mad_port_close(struct ib_device *device, int port_num)
2725 printk(KERN_ERR PFX "Port %d not found\n", port_num); 2734 printk(KERN_ERR PFX "Port %d not found\n", port_num);
2726 return -ENODEV; 2735 return -ENODEV;
2727 } 2736 }
2728 list_del(&port_priv->port_list); 2737 list_del_init(&port_priv->port_list);
2729 spin_unlock_irqrestore(&ib_mad_port_list_lock, flags); 2738 spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
2730 2739
2731 /* Stop processing completions. */
2732 flush_workqueue(port_priv->wq);
2733 destroy_workqueue(port_priv->wq); 2740 destroy_workqueue(port_priv->wq);
2734 destroy_mad_qp(&port_priv->qp_info[1]); 2741 destroy_mad_qp(&port_priv->qp_info[1]);
2735 destroy_mad_qp(&port_priv->qp_info[0]); 2742 destroy_mad_qp(&port_priv->qp_info[0]);