]> err.no Git - linux-2.6/commitdiff
RDMA/amso1100: Prevent deadlock in destroy QP
authorKrishna Kumar <krkumar2@in.ibm.com>
Fri, 24 Nov 2006 10:33:48 +0000 (16:03 +0530)
committerRoland Dreier <rolandd@cisco.com>
Wed, 29 Nov 2006 23:33:08 +0000 (15:33 -0800)
It is possible to swap the CQs used for send_cq and recv_cq when
creating two different QPs.  If these two QPs are then destroyed at
the same time, an AB-BA deadlock can occur because the CQ locks are
taken our of order.  Fix this by always taking CQ locks in a fixed
order.

Signed-off-by: Krishna Kumar <krkumar2@in.ibm.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/infiniband/hw/amso1100/c2_qp.c

index 5bcf697aa335bace362fcb3ecc86de5ed58e0eb5..179d005ed4a52f18293f76b432b7117169f64c75 100644 (file)
@@ -564,6 +564,32 @@ int c2_alloc_qp(struct c2_dev *c2dev,
        return err;
 }
 
+static inline void c2_lock_cqs(struct c2_cq *send_cq, struct c2_cq *recv_cq)
+{
+       if (send_cq == recv_cq)
+               spin_lock_irq(&send_cq->lock);
+       else if (send_cq > recv_cq) {
+               spin_lock_irq(&send_cq->lock);
+               spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING);
+       } else {
+               spin_lock_irq(&recv_cq->lock);
+               spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING);
+       }
+}
+
+static inline void c2_unlock_cqs(struct c2_cq *send_cq, struct c2_cq *recv_cq)
+{
+       if (send_cq == recv_cq)
+               spin_unlock_irq(&send_cq->lock);
+       else if (send_cq > recv_cq) {
+               spin_unlock(&recv_cq->lock);
+               spin_unlock_irq(&send_cq->lock);
+       } else {
+               spin_unlock(&send_cq->lock);
+               spin_unlock_irq(&recv_cq->lock);
+       }
+}
+
 void c2_free_qp(struct c2_dev *c2dev, struct c2_qp *qp)
 {
        struct c2_cq *send_cq;
@@ -576,15 +602,9 @@ void c2_free_qp(struct c2_dev *c2dev, struct c2_qp *qp)
         * Lock CQs here, so that CQ polling code can do QP lookup
         * without taking a lock.
         */
-       spin_lock_irq(&send_cq->lock);
-       if (send_cq != recv_cq)
-               spin_lock(&recv_cq->lock);
-
+       c2_lock_cqs(send_cq, recv_cq);
        c2_free_qpn(c2dev, qp->qpn);
-
-       if (send_cq != recv_cq)
-               spin_unlock(&recv_cq->lock);
-       spin_unlock_irq(&send_cq->lock);
+       c2_unlock_cqs(send_cq, recv_cq);
 
        /*
         * Destory qp in the rnic...