[openib-general] [PATCH] for 2.6.17: mad: fix queuing work item after destroying wq
Sean Hefty
sean.hefty at intel.com
Tue Mar 28 16:36:57 PST 2006
Fix an oopsable race debugged by Eli Cohen. 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 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 at mellanox.co.il>
Signed-off-by: Sean Hefty <sean.hefty at intel.com>
---
drivers/infiniband/core/mad.c | 21 ++++++++++++++-------
1 files changed, 14 insertions(+), 7 deletions(-)
4bf096f7c91b67d48a3f63f6395d762b583886ee
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 16549ad..f7854b6 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -2364,8 +2364,12 @@ static void timeout_sends(void *data)
static void ib_mad_thread_completion_handler(struct ib_cq *cq, void *arg)
{
struct ib_mad_port_private *port_priv = cq->cq_context;
+ unsigned long flags;
- queue_work(port_priv->wq, &port_priv->work);
+ spin_lock_irqsave(&ib_mad_port_list_lock, flags);
+ if (!list_empty(&port_priv->port_list))
+ queue_work(port_priv->wq, &port_priv->work);
+ spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
}
/*
@@ -2677,18 +2681,23 @@ static int ib_mad_port_open(struct ib_de
}
INIT_WORK(&port_priv->work, ib_mad_completion_handler, port_priv);
+ spin_lock_irqsave(&ib_mad_port_list_lock, flags);
+ list_add_tail(&port_priv->port_list, &ib_mad_port_list);
+ spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
+
ret = ib_mad_port_start(port_priv);
if (ret) {
printk(KERN_ERR PFX "Couldn't start port\n");
goto error9;
}
- spin_lock_irqsave(&ib_mad_port_list_lock, flags);
- list_add_tail(&port_priv->port_list, &ib_mad_port_list);
- spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
return 0;
error9:
+ spin_lock_irqsave(&ib_mad_port_list_lock, flags);
+ list_del_init(&port_priv->port_list);
+ spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
+
destroy_workqueue(port_priv->wq);
error8:
destroy_mad_qp(&port_priv->qp_info[1]);
@@ -2725,11 +2734,9 @@ static int ib_mad_port_close(struct ib_d
printk(KERN_ERR PFX "Port %d not found\n", port_num);
return -ENODEV;
}
- list_del(&port_priv->port_list);
+ list_del_init(&port_priv->port_list);
spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
- /* Stop processing completions. */
- flush_workqueue(port_priv->wq);
destroy_workqueue(port_priv->wq);
destroy_mad_qp(&port_priv->qp_info[1]);
destroy_mad_qp(&port_priv->qp_info[0]);
--
1.0.6
More information about the general
mailing list