diff options
author | Steve Wise <swise@opengridcomputing.com> | 2011-05-13 14:37:18 -0400 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2011-05-24 13:01:04 -0400 |
commit | 807838686eb9e40d73b8a3f2384881358f51fff0 (patch) | |
tree | 13ab2b82122044054693e949513500bbc8967aef /drivers/infiniband | |
parent | 257313b2a87795e07a0bdf58d0fffbdba8b31051 (diff) |
RDMA/cxgb3: Don't post zero-byte read if endpoint is going away
tx_ack() wasn't checking the endpoint state and consequently would
attempt to post the p2p 0B read on an endpoint/QP that is closing or
aborting. This causes a NULL pointer dereference crash.
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/cxgb3/iwch_cm.c | 26 | ||||
-rw-r--r-- | drivers/infiniband/hw/cxgb3/iwch_provider.h | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/cxgb3/iwch_qp.c | 6 |
3 files changed, 21 insertions, 13 deletions
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 3216bcad7e82..ad998c0b51e2 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c | |||
@@ -913,7 +913,7 @@ static void process_mpa_reply(struct iwch_ep *ep, struct sk_buff *skb) | |||
913 | goto err; | 913 | goto err; |
914 | 914 | ||
915 | if (peer2peer && iwch_rqes_posted(ep->com.qp) == 0) { | 915 | if (peer2peer && iwch_rqes_posted(ep->com.qp) == 0) { |
916 | iwch_post_zb_read(ep->com.qp); | 916 | iwch_post_zb_read(ep); |
917 | } | 917 | } |
918 | 918 | ||
919 | goto out; | 919 | goto out; |
@@ -1077,6 +1077,8 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) | |||
1077 | struct iwch_ep *ep = ctx; | 1077 | struct iwch_ep *ep = ctx; |
1078 | struct cpl_wr_ack *hdr = cplhdr(skb); | 1078 | struct cpl_wr_ack *hdr = cplhdr(skb); |
1079 | unsigned int credits = ntohs(hdr->credits); | 1079 | unsigned int credits = ntohs(hdr->credits); |
1080 | unsigned long flags; | ||
1081 | int post_zb = 0; | ||
1080 | 1082 | ||
1081 | PDBG("%s ep %p credits %u\n", __func__, ep, credits); | 1083 | PDBG("%s ep %p credits %u\n", __func__, ep, credits); |
1082 | 1084 | ||
@@ -1086,28 +1088,34 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) | |||
1086 | return CPL_RET_BUF_DONE; | 1088 | return CPL_RET_BUF_DONE; |
1087 | } | 1089 | } |
1088 | 1090 | ||
1091 | spin_lock_irqsave(&ep->com.lock, flags); | ||
1089 | BUG_ON(credits != 1); | 1092 | BUG_ON(credits != 1); |
1090 | dst_confirm(ep->dst); | 1093 | dst_confirm(ep->dst); |
1091 | if (!ep->mpa_skb) { | 1094 | if (!ep->mpa_skb) { |
1092 | PDBG("%s rdma_init wr_ack ep %p state %u\n", | 1095 | PDBG("%s rdma_init wr_ack ep %p state %u\n", |
1093 | __func__, ep, state_read(&ep->com)); | 1096 | __func__, ep, ep->com.state); |
1094 | if (ep->mpa_attr.initiator) { | 1097 | if (ep->mpa_attr.initiator) { |
1095 | PDBG("%s initiator ep %p state %u\n", | 1098 | PDBG("%s initiator ep %p state %u\n", |
1096 | __func__, ep, state_read(&ep->com)); | 1099 | __func__, ep, ep->com.state); |
1097 | if (peer2peer) | 1100 | if (peer2peer && ep->com.state == FPDU_MODE) |
1098 | iwch_post_zb_read(ep->com.qp); | 1101 | post_zb = 1; |
1099 | } else { | 1102 | } else { |
1100 | PDBG("%s responder ep %p state %u\n", | 1103 | PDBG("%s responder ep %p state %u\n", |
1101 | __func__, ep, state_read(&ep->com)); | 1104 | __func__, ep, ep->com.state); |
1102 | ep->com.rpl_done = 1; | 1105 | if (ep->com.state == MPA_REQ_RCVD) { |
1103 | wake_up(&ep->com.waitq); | 1106 | ep->com.rpl_done = 1; |
1107 | wake_up(&ep->com.waitq); | ||
1108 | } | ||
1104 | } | 1109 | } |
1105 | } else { | 1110 | } else { |
1106 | PDBG("%s lsm ack ep %p state %u freeing skb\n", | 1111 | PDBG("%s lsm ack ep %p state %u freeing skb\n", |
1107 | __func__, ep, state_read(&ep->com)); | 1112 | __func__, ep, ep->com.state); |
1108 | kfree_skb(ep->mpa_skb); | 1113 | kfree_skb(ep->mpa_skb); |
1109 | ep->mpa_skb = NULL; | 1114 | ep->mpa_skb = NULL; |
1110 | } | 1115 | } |
1116 | spin_unlock_irqrestore(&ep->com.lock, flags); | ||
1117 | if (post_zb) | ||
1118 | iwch_post_zb_read(ep); | ||
1111 | return CPL_RET_BUF_DONE; | 1119 | return CPL_RET_BUF_DONE; |
1112 | } | 1120 | } |
1113 | 1121 | ||
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h index c5406da3f4cd..9a342c9b220d 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.h +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h | |||
@@ -332,7 +332,7 @@ int iwch_bind_mw(struct ib_qp *qp, | |||
332 | struct ib_mw_bind *mw_bind); | 332 | struct ib_mw_bind *mw_bind); |
333 | int iwch_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc); | 333 | int iwch_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc); |
334 | int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg); | 334 | int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg); |
335 | int iwch_post_zb_read(struct iwch_qp *qhp); | 335 | int iwch_post_zb_read(struct iwch_ep *ep); |
336 | int iwch_register_device(struct iwch_dev *dev); | 336 | int iwch_register_device(struct iwch_dev *dev); |
337 | void iwch_unregister_device(struct iwch_dev *dev); | 337 | void iwch_unregister_device(struct iwch_dev *dev); |
338 | void stop_read_rep_timer(struct iwch_qp *qhp); | 338 | void stop_read_rep_timer(struct iwch_qp *qhp); |
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c index 1b4cd09f74dc..ecd313f359a4 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c | |||
@@ -738,7 +738,7 @@ static inline void build_term_codes(struct respQ_msg_t *rsp_msg, | |||
738 | } | 738 | } |
739 | } | 739 | } |
740 | 740 | ||
741 | int iwch_post_zb_read(struct iwch_qp *qhp) | 741 | int iwch_post_zb_read(struct iwch_ep *ep) |
742 | { | 742 | { |
743 | union t3_wr *wqe; | 743 | union t3_wr *wqe; |
744 | struct sk_buff *skb; | 744 | struct sk_buff *skb; |
@@ -761,10 +761,10 @@ int iwch_post_zb_read(struct iwch_qp *qhp) | |||
761 | wqe->read.local_len = cpu_to_be32(0); | 761 | wqe->read.local_len = cpu_to_be32(0); |
762 | wqe->read.local_to = cpu_to_be64(1); | 762 | wqe->read.local_to = cpu_to_be64(1); |
763 | wqe->send.wrh.op_seop_flags = cpu_to_be32(V_FW_RIWR_OP(T3_WR_READ)); | 763 | wqe->send.wrh.op_seop_flags = cpu_to_be32(V_FW_RIWR_OP(T3_WR_READ)); |
764 | wqe->send.wrh.gen_tid_len = cpu_to_be32(V_FW_RIWR_TID(qhp->ep->hwtid)| | 764 | wqe->send.wrh.gen_tid_len = cpu_to_be32(V_FW_RIWR_TID(ep->hwtid)| |
765 | V_FW_RIWR_LEN(flit_cnt)); | 765 | V_FW_RIWR_LEN(flit_cnt)); |
766 | skb->priority = CPL_PRIORITY_DATA; | 766 | skb->priority = CPL_PRIORITY_DATA; |
767 | return iwch_cxgb3_ofld_send(qhp->rhp->rdev.t3cdev_p, skb); | 767 | return iwch_cxgb3_ofld_send(ep->com.qp->rhp->rdev.t3cdev_p, skb); |
768 | } | 768 | } |
769 | 769 | ||
770 | /* | 770 | /* |