aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorSteve Wise <swise@opengridcomputing.com>2011-05-10 01:06:22 -0400
committerRoland Dreier <roland@purestorage.com>2011-05-10 01:06:22 -0400
commit30c95c2d495c1c8d4d6a97bb9f4e4eacb91ba1d2 (patch)
treeace5f0f3da8d942bc894f8ad0fbc6ceddda1d64d /drivers/infiniband
parent693d92a1bbc9e42681c42ed190bd42b636ca876f (diff)
RDMA/cxgb4: Don't change QP state outside EP lock
Concurrent ingress CLOSE and ULP ABORT operations causes a crash due to a race condition where the close path releases the EP lock and then tries to move the QP state to CLOSED. This must be done inside the EP lock to avoid the race. Signed-off-by: Steve Wise <swise@opengridcomputing.com> Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/hw/cxgb4/cm.c16
-rw-r--r--drivers/infiniband/hw/cxgb4/iw_cxgb4.h4
-rw-r--r--drivers/infiniband/hw/cxgb4/qp.c1
3 files changed, 9 insertions, 12 deletions
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 9d8dcfab2b38..d235810e52df 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -1466,7 +1466,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
1466 struct c4iw_qp_attributes attrs; 1466 struct c4iw_qp_attributes attrs;
1467 int disconnect = 1; 1467 int disconnect = 1;
1468 int release = 0; 1468 int release = 0;
1469 int closing = 0; 1469 int abort = 0;
1470 struct tid_info *t = dev->rdev.lldi.tids; 1470 struct tid_info *t = dev->rdev.lldi.tids;
1471 unsigned int tid = GET_TID(hdr); 1471 unsigned int tid = GET_TID(hdr);
1472 1472
@@ -1507,8 +1507,11 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
1507 case FPDU_MODE: 1507 case FPDU_MODE:
1508 start_ep_timer(ep); 1508 start_ep_timer(ep);
1509 __state_set(&ep->com, CLOSING); 1509 __state_set(&ep->com, CLOSING);
1510 closing = 1; 1510 attrs.next_state = C4IW_QP_STATE_CLOSING;
1511 abort = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
1512 C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
1511 peer_close_upcall(ep); 1513 peer_close_upcall(ep);
1514 disconnect = 1;
1512 break; 1515 break;
1513 case ABORTING: 1516 case ABORTING:
1514 disconnect = 0; 1517 disconnect = 0;
@@ -1536,11 +1539,6 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
1536 BUG_ON(1); 1539 BUG_ON(1);
1537 } 1540 }
1538 mutex_unlock(&ep->com.mutex); 1541 mutex_unlock(&ep->com.mutex);
1539 if (closing) {
1540 attrs.next_state = C4IW_QP_STATE_CLOSING;
1541 c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
1542 C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
1543 }
1544 if (disconnect) 1542 if (disconnect)
1545 c4iw_ep_disconnect(ep, 0, GFP_KERNEL); 1543 c4iw_ep_disconnect(ep, 0, GFP_KERNEL);
1546 if (release) 1544 if (release)
@@ -1710,14 +1708,14 @@ static int terminate(struct c4iw_dev *dev, struct sk_buff *skb)
1710 ep = lookup_tid(t, tid); 1708 ep = lookup_tid(t, tid);
1711 BUG_ON(!ep); 1709 BUG_ON(!ep);
1712 1710
1713 if (ep->com.qp) { 1711 if (ep && ep->com.qp) {
1714 printk(KERN_WARNING MOD "TERM received tid %u qpid %u\n", tid, 1712 printk(KERN_WARNING MOD "TERM received tid %u qpid %u\n", tid,
1715 ep->com.qp->wq.sq.qid); 1713 ep->com.qp->wq.sq.qid);
1716 attrs.next_state = C4IW_QP_STATE_TERMINATE; 1714 attrs.next_state = C4IW_QP_STATE_TERMINATE;
1717 c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, 1715 c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
1718 C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); 1716 C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
1719 } else 1717 } else
1720 printk(KERN_WARNING MOD "TERM received tid %u no qp\n", tid); 1718 printk(KERN_WARNING MOD "TERM received tid %u no ep/qp\n", tid);
1721 1719
1722 return 0; 1720 return 0;
1723} 1721}
diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
index 9f6166f59268..8e16eb2de91f 100644
--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
@@ -161,8 +161,8 @@ static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
161 } 161 }
162 } while (!wr_waitp->done); 162 } while (!wr_waitp->done);
163 if (wr_waitp->ret) 163 if (wr_waitp->ret)
164 printk(KERN_WARNING MOD "%s: FW reply %d tid %u qpid %u\n", 164 PDBG("%s: FW reply %d tid %u qpid %u\n",
165 pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid); 165 pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid);
166 return wr_waitp->ret; 166 return wr_waitp->ret;
167} 167}
168 168
diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
index 70a5a3c646da..a1824a5f3d76 100644
--- a/drivers/infiniband/hw/cxgb4/qp.c
+++ b/drivers/infiniband/hw/cxgb4/qp.c
@@ -1210,7 +1210,6 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
1210 if (ret) { 1210 if (ret) {
1211 if (internal) 1211 if (internal)
1212 c4iw_get_ep(&qhp->ep->com); 1212 c4iw_get_ep(&qhp->ep->com);
1213 disconnect = abort = 1;
1214 goto err; 1213 goto err;
1215 } 1214 }
1216 break; 1215 break;