aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorFaisal Latif <faisal.latif@intel.com>2009-12-09 18:54:08 -0500
committerRoland Dreier <rolandd@cisco.com>2009-12-09 18:54:08 -0500
commitc5a7d4897156667a58fd8479f6227143573fe82d (patch)
tree9f8fed3529b5aa1ea8e8a991668b15094127161f /drivers/infiniband
parent69524e1aff75e4ed8efcb7d699c97d55c317a950 (diff)
RDMA/nes: Fix crash in nes_accept()
While running IMP_EXT's window test, we saw a crash in nes_accept(). Here is the sequence of what happened: (1) In MVAPICH2, connect request is received for port #0. FIX: Add a nes_connect() check to make sure local or remote tcp port is not 0. (2) Remote node's (passive) TCP stack sends a reset when it gets a connect request because of port = 0. Active side set the connect error to IW_CM_EVENT_STATUS_REJECTED when it received the RST from remote node. FIX: The corect error code is -ECONNRESET. (3) Wrong error code of IW_CM_EVENT_STATUS_REJECTED causes the core to destroy its listener ports. Here there are connections that may have sent an MPA request up and waiting for accept or reject. But the listener and its cm_nodes have been freed already causing the crash noticed. FIX: The cm_node is freed only if its state is not NES_CM_STATE_MPAREQ_RCVD. If cm_node's state is NES_CM_STATE_MPAREQ_RCVD then its new state is set to NES_CM_STATE_LISTENER_DESTROYED and it is not freed. When nes_accept() or nes_reject() is received, its state is checked for NES_CM_STATE_LISTENER_DESTROYED and in this case the cm_node is freed and error is returned. Signed-off-by: Faisal Latif <faisal.latif@intel.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c77
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.h1
2 files changed, 50 insertions, 28 deletions
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 08fcd25f788c..ec04786b6069 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -978,6 +978,7 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
978 reset_entry); 978 reset_entry);
979 { 979 {
980 struct nes_cm_node *loopback = cm_node->loopbackpartner; 980 struct nes_cm_node *loopback = cm_node->loopbackpartner;
981 enum nes_cm_node_state old_state;
981 if (NES_CM_STATE_FIN_WAIT1 <= cm_node->state) { 982 if (NES_CM_STATE_FIN_WAIT1 <= cm_node->state) {
982 rem_ref_cm_node(cm_node->cm_core, cm_node); 983 rem_ref_cm_node(cm_node->cm_core, cm_node);
983 } else { 984 } else {
@@ -989,11 +990,12 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
989 NES_CM_STATE_CLOSED; 990 NES_CM_STATE_CLOSED;
990 WARN_ON(1); 991 WARN_ON(1);
991 } else { 992 } else {
992 cm_node->state = 993 old_state = cm_node->state;
993 NES_CM_STATE_CLOSED; 994 cm_node->state = NES_CM_STATE_LISTENER_DESTROYED;
994 rem_ref_cm_node( 995 if (old_state != NES_CM_STATE_MPAREQ_RCVD)
995 cm_node->cm_core, 996 rem_ref_cm_node(
996 cm_node); 997 cm_node->cm_core,
998 cm_node);
997 } 999 }
998 } else { 1000 } else {
999 struct nes_cm_event event; 1001 struct nes_cm_event event;
@@ -1009,6 +1011,7 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
1009 loopback->loc_port; 1011 loopback->loc_port;
1010 event.cm_info.cm_id = loopback->cm_id; 1012 event.cm_info.cm_id = loopback->cm_id;
1011 cm_event_connect_error(&event); 1013 cm_event_connect_error(&event);
1014 cm_node->state = NES_CM_STATE_LISTENER_DESTROYED;
1012 loopback->state = NES_CM_STATE_CLOSED; 1015 loopback->state = NES_CM_STATE_CLOSED;
1013 1016
1014 event.cm_node = cm_node; 1017 event.cm_node = cm_node;
@@ -2131,30 +2134,39 @@ static int mini_cm_reject(struct nes_cm_core *cm_core,
2131 cm_node->state = NES_CM_STATE_CLOSED; 2134 cm_node->state = NES_CM_STATE_CLOSED;
2132 rem_ref_cm_node(cm_core, cm_node); 2135 rem_ref_cm_node(cm_core, cm_node);
2133 } else { 2136 } else {
2134 ret = send_mpa_reject(cm_node); 2137 if (cm_node->state == NES_CM_STATE_LISTENER_DESTROYED) {
2135 if (ret) { 2138 rem_ref_cm_node(cm_core, cm_node);
2136 cm_node->state = NES_CM_STATE_CLOSED; 2139 } else {
2137 err = send_reset(cm_node, NULL); 2140 ret = send_mpa_reject(cm_node);
2138 if (err) 2141 if (ret) {
2139 WARN_ON(1); 2142 cm_node->state = NES_CM_STATE_CLOSED;
2140 } else 2143 err = send_reset(cm_node, NULL);
2141 cm_id->add_ref(cm_id); 2144 if (err)
2145 WARN_ON(1);
2146 } else
2147 cm_id->add_ref(cm_id);
2148 }
2142 } 2149 }
2143 } else { 2150 } else {
2144 cm_node->cm_id = NULL; 2151 cm_node->cm_id = NULL;
2145 event.cm_node = loopback; 2152 if (cm_node->state == NES_CM_STATE_LISTENER_DESTROYED) {
2146 event.cm_info.rem_addr = loopback->rem_addr; 2153 rem_ref_cm_node(cm_core, cm_node);
2147 event.cm_info.loc_addr = loopback->loc_addr; 2154 rem_ref_cm_node(cm_core, loopback);
2148 event.cm_info.rem_port = loopback->rem_port; 2155 } else {
2149 event.cm_info.loc_port = loopback->loc_port; 2156 event.cm_node = loopback;
2150 event.cm_info.cm_id = loopback->cm_id; 2157 event.cm_info.rem_addr = loopback->rem_addr;
2151 cm_event_mpa_reject(&event); 2158 event.cm_info.loc_addr = loopback->loc_addr;
2152 rem_ref_cm_node(cm_core, cm_node); 2159 event.cm_info.rem_port = loopback->rem_port;
2153 loopback->state = NES_CM_STATE_CLOSING; 2160 event.cm_info.loc_port = loopback->loc_port;
2161 event.cm_info.cm_id = loopback->cm_id;
2162 cm_event_mpa_reject(&event);
2163 rem_ref_cm_node(cm_core, cm_node);
2164 loopback->state = NES_CM_STATE_CLOSING;
2154 2165
2155 cm_id = loopback->cm_id; 2166 cm_id = loopback->cm_id;
2156 rem_ref_cm_node(cm_core, loopback); 2167 rem_ref_cm_node(cm_core, loopback);
2157 cm_id->rem_ref(cm_id); 2168 cm_id->rem_ref(cm_id);
2169 }
2158 } 2170 }
2159 2171
2160 return ret; 2172 return ret;
@@ -2198,6 +2210,7 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod
2198 case NES_CM_STATE_UNKNOWN: 2210 case NES_CM_STATE_UNKNOWN:
2199 case NES_CM_STATE_INITED: 2211 case NES_CM_STATE_INITED:
2200 case NES_CM_STATE_CLOSED: 2212 case NES_CM_STATE_CLOSED:
2213 case NES_CM_STATE_LISTENER_DESTROYED:
2201 ret = rem_ref_cm_node(cm_core, cm_node); 2214 ret = rem_ref_cm_node(cm_core, cm_node);
2202 break; 2215 break;
2203 case NES_CM_STATE_TSA: 2216 case NES_CM_STATE_TSA:
@@ -2716,8 +2729,6 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
2716 struct nes_pd *nespd; 2729 struct nes_pd *nespd;
2717 u64 tagged_offset; 2730 u64 tagged_offset;
2718 2731
2719
2720
2721 ibqp = nes_get_qp(cm_id->device, conn_param->qpn); 2732 ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
2722 if (!ibqp) 2733 if (!ibqp)
2723 return -EINVAL; 2734 return -EINVAL;
@@ -2733,6 +2744,13 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
2733 "%s\n", cm_node, nesvnic, nesvnic->netdev, 2744 "%s\n", cm_node, nesvnic, nesvnic->netdev,
2734 nesvnic->netdev->name); 2745 nesvnic->netdev->name);
2735 2746
2747 if (NES_CM_STATE_LISTENER_DESTROYED == cm_node->state) {
2748 if (cm_node->loopbackpartner)
2749 rem_ref_cm_node(cm_node->cm_core, cm_node->loopbackpartner);
2750 rem_ref_cm_node(cm_node->cm_core, cm_node);
2751 return -EINVAL;
2752 }
2753
2736 /* associate the node with the QP */ 2754 /* associate the node with the QP */
2737 nesqp->cm_node = (void *)cm_node; 2755 nesqp->cm_node = (void *)cm_node;
2738 cm_node->nesqp = nesqp; 2756 cm_node->nesqp = nesqp;
@@ -3003,6 +3021,9 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
3003 if (!nesdev) 3021 if (!nesdev)
3004 return -EINVAL; 3022 return -EINVAL;
3005 3023
3024 if (!(cm_id->local_addr.sin_port) || !(cm_id->remote_addr.sin_port))
3025 return -EINVAL;
3026
3006 nes_debug(NES_DBG_CM, "QP%u, current IP = 0x%08X, Destination IP = " 3027 nes_debug(NES_DBG_CM, "QP%u, current IP = 0x%08X, Destination IP = "
3007 "0x%08X:0x%04X, local = 0x%08X:0x%04X.\n", nesqp->hwqp.qp_id, 3028 "0x%08X:0x%04X, local = 0x%08X:0x%04X.\n", nesqp->hwqp.qp_id,
3008 ntohl(nesvnic->local_ipaddr), 3029 ntohl(nesvnic->local_ipaddr),
@@ -3375,7 +3396,7 @@ static void cm_event_connect_error(struct nes_cm_event *event)
3375 nesqp->cm_id = NULL; 3396 nesqp->cm_id = NULL;
3376 cm_id->provider_data = NULL; 3397 cm_id->provider_data = NULL;
3377 cm_event.event = IW_CM_EVENT_CONNECT_REPLY; 3398 cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
3378 cm_event.status = IW_CM_EVENT_STATUS_REJECTED; 3399 cm_event.status = -ECONNRESET;
3379 cm_event.provider_data = cm_id->provider_data; 3400 cm_event.provider_data = cm_id->provider_data;
3380 cm_event.local_addr = cm_id->local_addr; 3401 cm_event.local_addr = cm_id->local_addr;
3381 cm_event.remote_addr = cm_id->remote_addr; 3402 cm_event.remote_addr = cm_id->remote_addr;
diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h
index 911846ae5c7d..d9825fda70a1 100644
--- a/drivers/infiniband/hw/nes/nes_cm.h
+++ b/drivers/infiniband/hw/nes/nes_cm.h
@@ -200,6 +200,7 @@ enum nes_cm_node_state {
200 NES_CM_STATE_TIME_WAIT, 200 NES_CM_STATE_TIME_WAIT,
201 NES_CM_STATE_LAST_ACK, 201 NES_CM_STATE_LAST_ACK,
202 NES_CM_STATE_CLOSING, 202 NES_CM_STATE_CLOSING,
203 NES_CM_STATE_LISTENER_DESTROYED,
203 NES_CM_STATE_CLOSED 204 NES_CM_STATE_CLOSED
204}; 205};
205 206