[openib-general] Re: [PATCH] cm refcount race fix
Roland Dreier
rdreier at cisco.com
Mon May 8 12:07:59 PDT 2006
It does seem we can simplify mthca_cq in a slightly different way.
mthca_cq_clean() doesn't need to take a CQ reference, because we know
the CQ can't go away before all associated QPs are gone, and at least
one QP will stay around until mthca_cq_clean() returns.
So the below patch is both a fix and a decent cleanup:
--- infiniband/hw/mthca/mthca_provider.h (revision 6945)
+++ infiniband/hw/mthca/mthca_provider.h (working copy)
@@ -197,7 +197,7 @@ struct mthca_cq_resize {
struct mthca_cq {
struct ib_cq ibcq;
spinlock_t lock;
- atomic_t refcount;
+ int refcount;
int cqn;
u32 cons_index;
struct mthca_cq_buf buf;
--- infiniband/hw/mthca/mthca_dev.h (revision 6945)
+++ infiniband/hw/mthca/mthca_dev.h (working copy)
@@ -496,7 +496,7 @@ void mthca_free_cq(struct mthca_dev *dev
void mthca_cq_completion(struct mthca_dev *dev, u32 cqn);
void mthca_cq_event(struct mthca_dev *dev, u32 cqn,
enum ib_event_type event_type);
-void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
+void mthca_cq_clean(struct mthca_dev *dev, struct mthca_cq *cq, u32 qpn,
struct mthca_srq *srq);
void mthca_cq_resize_copy_cqes(struct mthca_cq *cq);
int mthca_alloc_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int nent);
--- infiniband/hw/mthca/mthca_cq.c (revision 6945)
+++ infiniband/hw/mthca/mthca_cq.c (working copy)
@@ -234,14 +234,19 @@ void mthca_cq_event(struct mthca_dev *de
{
struct mthca_cq *cq;
struct ib_event event;
+ unsigned long flags;
- spin_lock(&dev->cq_table.lock);
+ spin_lock_irqsave(&dev->cq_table.lock, flags);
cq = mthca_array_get(&dev->cq_table.cq, cqn & (dev->limits.num_cqs - 1));
- if (cq)
- atomic_inc(&cq->refcount);
- spin_unlock(&dev->cq_table.lock);
+ if (cq) {
+ spin_lock(&cq->lock);
+ ++cq->refcount;
+ spin_unlock(&cq->lock);
+ }
+
+ spin_unlock_irqrestore(&dev->cq_table.lock, flags);
if (!cq) {
mthca_warn(dev, "Async event for bogus CQ %08x\n", cqn);
@@ -254,8 +259,10 @@ void mthca_cq_event(struct mthca_dev *de
if (cq->ibcq.event_handler)
cq->ibcq.event_handler(&event, cq->ibcq.cq_context);
- if (atomic_dec_and_test(&cq->refcount))
+ spin_lock_irqsave(&cq->lock, flags);
+ if (!--cq->refcount)
wake_up(&cq->wait);
+ spin_unlock_irqrestore(&cq->lock, flags);
}
static inline int is_recv_cqe(struct mthca_cqe *cqe)
@@ -267,23 +274,13 @@ static inline int is_recv_cqe(struct mth
return !(cqe->is_send & 0x80);
}
-void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
+void mthca_cq_clean(struct mthca_dev *dev, struct mthca_cq *cq, u32 qpn,
struct mthca_srq *srq)
{
- struct mthca_cq *cq;
struct mthca_cqe *cqe;
u32 prod_index;
int nfreed = 0;
- spin_lock_irq(&dev->cq_table.lock);
- cq = mthca_array_get(&dev->cq_table.cq, cqn & (dev->limits.num_cqs - 1));
- if (cq)
- atomic_inc(&cq->refcount);
- spin_unlock_irq(&dev->cq_table.lock);
-
- if (!cq)
- return;
-
spin_lock_irq(&cq->lock);
/*
@@ -301,7 +298,7 @@ void mthca_cq_clean(struct mthca_dev *de
if (0)
mthca_dbg(dev, "Cleaning QPN %06x from CQN %06x; ci %d, pi %d\n",
- qpn, cqn, cq->cons_index, prod_index);
+ qpn, cq->cqn, cq->cons_index, prod_index);
/*
* Now sweep backwards through the CQ, removing CQ entries
@@ -323,10 +320,6 @@ void mthca_cq_clean(struct mthca_dev *de
cq->cons_index += nfreed;
update_cons_index(dev, cq, nfreed);
}
-
- spin_unlock_irq(&cq->lock);
- if (atomic_dec_and_test(&cq->refcount))
- wake_up(&cq->wait);
}
void mthca_cq_resize_copy_cqes(struct mthca_cq *cq)
@@ -821,7 +814,7 @@ int mthca_init_cq(struct mthca_dev *dev,
}
spin_lock_init(&cq->lock);
- atomic_set(&cq->refcount, 1);
+ cq->refcount = 1;
init_waitqueue_head(&cq->wait);
memset(cq_context, 0, sizeof *cq_context);
@@ -896,6 +889,17 @@ err_out:
return err;
}
+static int get_cq_refcount(struct mthca_cq *cq)
+{
+ int c;
+
+ spin_lock_irq(&cq->lock);
+ c = cq->refcount;
+ spin_unlock_irq(&cq->lock);
+
+ return c;
+}
+
void mthca_free_cq(struct mthca_dev *dev,
struct mthca_cq *cq)
{
@@ -936,8 +940,11 @@ void mthca_free_cq(struct mthca_dev *dev
else
synchronize_irq(dev->pdev->irq);
- atomic_dec(&cq->refcount);
- wait_event(cq->wait, !atomic_read(&cq->refcount));
+ spin_lock_irq(&cq->lock);
+ --cq->refcount;
+ spin_unlock_irq(&cq->lock);
+
+ wait_event(cq->wait, !get_cq_refcount(cq));
if (cq->is_kernel) {
mthca_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe);
--- infiniband/hw/mthca/mthca_qp.c (revision 6945)
+++ infiniband/hw/mthca/mthca_qp.c (working copy)
@@ -831,10 +831,10 @@ int mthca_modify_qp(struct ib_qp *ibqp,
* entries and reinitialize the QP.
*/
if (new_state == IB_QPS_RESET && !qp->ibqp.uobject) {
- mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn,
+ mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq), qp->qpn,
qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
if (qp->ibqp.send_cq != qp->ibqp.recv_cq)
- mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn,
+ mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn,
qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
mthca_wq_init(&qp->sq);
@@ -1356,10 +1356,10 @@ void mthca_free_qp(struct mthca_dev *dev
* unref the mem-free tables and free the QPN in our table.
*/
if (!qp->ibqp.uobject) {
- mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn,
+ mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq), qp->qpn,
qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
if (qp->ibqp.send_cq != qp->ibqp.recv_cq)
- mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn,
+ mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn,
qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
mthca_free_memfree(dev, qp);
More information about the general
mailing list