diff options
author | Faisal Latif <faisal.latif@intel.com> | 2008-11-21 21:50:46 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2008-12-05 14:00:08 -0500 |
commit | 183ecfa3091cd4cdda329a7fe89d9544088f517d (patch) | |
tree | 5cccb1b5b0fdfe7ec1dbaddbe0de04ce087f99a8 /drivers/infiniband | |
parent | 879e5bd5a1a0a317fb67fa4dc550db092a7bdcb0 (diff) |
RDMA/nes: Avoid race between MPA request and reset event to rdma_cm
In passive open, after indicating MPA request to rdma_cm, an incoming
RST would fire a reset event to rdma_cm causing it to crash, since the
current state is not connected. The solution is to wait for
nes_accept() or nes_reject() before firing the reset event. If
nes_accept() or nes_reject() is already done, then the reset event
will be fired when RST is processed.
Signed-off-by: Faisal Latif <faisal.latif@intel.com>
Signed-off-by: Chien Tung <chien.tin.tung@intel.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/hw/nes/nes_cm.c | 50 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_cm.h | 5 |
2 files changed, 49 insertions, 6 deletions
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 257d994ec7b5..c259ddc8dd88 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c | |||
@@ -1360,6 +1360,7 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, | |||
1360 | { | 1360 | { |
1361 | 1361 | ||
1362 | int reset = 0; /* whether to send reset in case of err.. */ | 1362 | int reset = 0; /* whether to send reset in case of err.. */ |
1363 | int passive_state; | ||
1363 | atomic_inc(&cm_resets_recvd); | 1364 | atomic_inc(&cm_resets_recvd); |
1364 | nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u." | 1365 | nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u." |
1365 | " refcnt=%d\n", cm_node, cm_node->state, | 1366 | " refcnt=%d\n", cm_node, cm_node->state, |
@@ -1373,7 +1374,14 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, | |||
1373 | cm_node->listener, cm_node->state); | 1374 | cm_node->listener, cm_node->state); |
1374 | active_open_err(cm_node, skb, reset); | 1375 | active_open_err(cm_node, skb, reset); |
1375 | break; | 1376 | break; |
1376 | /* For PASSIVE open states, remove the cm_node event */ | 1377 | case NES_CM_STATE_MPAREQ_RCVD: |
1378 | passive_state = atomic_add_return(1, &cm_node->passive_state); | ||
1379 | if (passive_state == NES_SEND_RESET_EVENT) | ||
1380 | create_event(cm_node, NES_CM_EVENT_RESET); | ||
1381 | cleanup_retrans_entry(cm_node); | ||
1382 | cm_node->state = NES_CM_STATE_CLOSED; | ||
1383 | dev_kfree_skb_any(skb); | ||
1384 | break; | ||
1377 | case NES_CM_STATE_ESTABLISHED: | 1385 | case NES_CM_STATE_ESTABLISHED: |
1378 | case NES_CM_STATE_SYN_RCVD: | 1386 | case NES_CM_STATE_SYN_RCVD: |
1379 | case NES_CM_STATE_LISTENING: | 1387 | case NES_CM_STATE_LISTENING: |
@@ -1381,7 +1389,14 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, | |||
1381 | passive_open_err(cm_node, skb, reset); | 1389 | passive_open_err(cm_node, skb, reset); |
1382 | break; | 1390 | break; |
1383 | case NES_CM_STATE_TSA: | 1391 | case NES_CM_STATE_TSA: |
1392 | active_open_err(cm_node, skb, reset); | ||
1393 | break; | ||
1394 | case NES_CM_STATE_CLOSED: | ||
1395 | cleanup_retrans_entry(cm_node); | ||
1396 | drop_packet(skb); | ||
1397 | break; | ||
1384 | default: | 1398 | default: |
1399 | drop_packet(skb); | ||
1385 | break; | 1400 | break; |
1386 | } | 1401 | } |
1387 | } | 1402 | } |
@@ -1410,6 +1425,9 @@ static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb, | |||
1410 | dev_kfree_skb_any(skb); | 1425 | dev_kfree_skb_any(skb); |
1411 | if (type == NES_CM_EVENT_CONNECTED) | 1426 | if (type == NES_CM_EVENT_CONNECTED) |
1412 | cm_node->state = NES_CM_STATE_TSA; | 1427 | cm_node->state = NES_CM_STATE_TSA; |
1428 | else | ||
1429 | atomic_set(&cm_node->passive_state, | ||
1430 | NES_PASSIVE_STATE_INDICATED); | ||
1413 | create_event(cm_node, type); | 1431 | create_event(cm_node, type); |
1414 | 1432 | ||
1415 | } | 1433 | } |
@@ -1986,6 +2004,7 @@ static int mini_cm_reject(struct nes_cm_core *cm_core, | |||
1986 | struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node) | 2004 | struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node) |
1987 | { | 2005 | { |
1988 | int ret = 0; | 2006 | int ret = 0; |
2007 | int passive_state; | ||
1989 | 2008 | ||
1990 | nes_debug(NES_DBG_CM, "%s cm_node=%p type=%d state=%d\n", | 2009 | nes_debug(NES_DBG_CM, "%s cm_node=%p type=%d state=%d\n", |
1991 | __func__, cm_node, cm_node->tcp_cntxt.client, cm_node->state); | 2010 | __func__, cm_node, cm_node->tcp_cntxt.client, cm_node->state); |
@@ -1993,9 +2012,13 @@ static int mini_cm_reject(struct nes_cm_core *cm_core, | |||
1993 | if (cm_node->tcp_cntxt.client) | 2012 | if (cm_node->tcp_cntxt.client) |
1994 | return ret; | 2013 | return ret; |
1995 | cleanup_retrans_entry(cm_node); | 2014 | cleanup_retrans_entry(cm_node); |
1996 | cm_node->state = NES_CM_STATE_CLOSED; | ||
1997 | 2015 | ||
1998 | ret = send_reset(cm_node, NULL); | 2016 | passive_state = atomic_add_return(1, &cm_node->passive_state); |
2017 | cm_node->state = NES_CM_STATE_CLOSED; | ||
2018 | if (passive_state == NES_SEND_RESET_EVENT) | ||
2019 | rem_ref_cm_node(cm_core, cm_node); | ||
2020 | else | ||
2021 | ret = send_reset(cm_node, NULL); | ||
1999 | return ret; | 2022 | return ret; |
2000 | } | 2023 | } |
2001 | 2024 | ||
@@ -2413,7 +2436,6 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) | |||
2413 | atomic_inc(&cm_disconnects); | 2436 | atomic_inc(&cm_disconnects); |
2414 | cm_event.event = IW_CM_EVENT_DISCONNECT; | 2437 | cm_event.event = IW_CM_EVENT_DISCONNECT; |
2415 | if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) { | 2438 | if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) { |
2416 | issued_disconnect_reset = 1; | ||
2417 | cm_event.status = IW_CM_EVENT_STATUS_RESET; | 2439 | cm_event.status = IW_CM_EVENT_STATUS_RESET; |
2418 | nes_debug(NES_DBG_CM, "Generating a CM " | 2440 | nes_debug(NES_DBG_CM, "Generating a CM " |
2419 | "Disconnect Event (status reset) for " | 2441 | "Disconnect Event (status reset) for " |
@@ -2563,6 +2585,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) | |||
2563 | struct nes_v4_quad nes_quad; | 2585 | struct nes_v4_quad nes_quad; |
2564 | u32 crc_value; | 2586 | u32 crc_value; |
2565 | int ret; | 2587 | int ret; |
2588 | int passive_state; | ||
2566 | 2589 | ||
2567 | ibqp = nes_get_qp(cm_id->device, conn_param->qpn); | 2590 | ibqp = nes_get_qp(cm_id->device, conn_param->qpn); |
2568 | if (!ibqp) | 2591 | if (!ibqp) |
@@ -2730,8 +2753,6 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) | |||
2730 | conn_param->private_data_len + | 2753 | conn_param->private_data_len + |
2731 | sizeof(struct ietf_mpa_frame)); | 2754 | sizeof(struct ietf_mpa_frame)); |
2732 | 2755 | ||
2733 | attr.qp_state = IB_QPS_RTS; | ||
2734 | nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL); | ||
2735 | 2756 | ||
2736 | /* notify OF layer that accept event was successfull */ | 2757 | /* notify OF layer that accept event was successfull */ |
2737 | cm_id->add_ref(cm_id); | 2758 | cm_id->add_ref(cm_id); |
@@ -2744,6 +2765,8 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) | |||
2744 | cm_event.private_data = NULL; | 2765 | cm_event.private_data = NULL; |
2745 | cm_event.private_data_len = 0; | 2766 | cm_event.private_data_len = 0; |
2746 | ret = cm_id->event_handler(cm_id, &cm_event); | 2767 | ret = cm_id->event_handler(cm_id, &cm_event); |
2768 | attr.qp_state = IB_QPS_RTS; | ||
2769 | nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL); | ||
2747 | if (cm_node->loopbackpartner) { | 2770 | if (cm_node->loopbackpartner) { |
2748 | cm_node->loopbackpartner->mpa_frame_size = | 2771 | cm_node->loopbackpartner->mpa_frame_size = |
2749 | nesqp->private_data_len; | 2772 | nesqp->private_data_len; |
@@ -2756,6 +2779,9 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) | |||
2756 | printk(KERN_ERR "%s[%u] OFA CM event_handler returned, " | 2779 | printk(KERN_ERR "%s[%u] OFA CM event_handler returned, " |
2757 | "ret=%d\n", __func__, __LINE__, ret); | 2780 | "ret=%d\n", __func__, __LINE__, ret); |
2758 | 2781 | ||
2782 | passive_state = atomic_add_return(1, &cm_node->passive_state); | ||
2783 | if (passive_state == NES_SEND_RESET_EVENT) | ||
2784 | create_event(cm_node, NES_CM_EVENT_RESET); | ||
2759 | return 0; | 2785 | return 0; |
2760 | } | 2786 | } |
2761 | 2787 | ||
@@ -3238,6 +3264,18 @@ static void cm_event_reset(struct nes_cm_event *event) | |||
3238 | cm_event.private_data_len = 0; | 3264 | cm_event.private_data_len = 0; |
3239 | 3265 | ||
3240 | ret = cm_id->event_handler(cm_id, &cm_event); | 3266 | ret = cm_id->event_handler(cm_id, &cm_event); |
3267 | cm_id->add_ref(cm_id); | ||
3268 | atomic_inc(&cm_closes); | ||
3269 | cm_event.event = IW_CM_EVENT_CLOSE; | ||
3270 | cm_event.status = IW_CM_EVENT_STATUS_OK; | ||
3271 | cm_event.provider_data = cm_id->provider_data; | ||
3272 | cm_event.local_addr = cm_id->local_addr; | ||
3273 | cm_event.remote_addr = cm_id->remote_addr; | ||
3274 | cm_event.private_data = NULL; | ||
3275 | cm_event.private_data_len = 0; | ||
3276 | nes_debug(NES_DBG_CM, "NODE %p Generating CLOSE\n", event->cm_node); | ||
3277 | ret = cm_id->event_handler(cm_id, &cm_event); | ||
3278 | |||
3241 | nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret); | 3279 | nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret); |
3242 | 3280 | ||
3243 | 3281 | ||
diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h index 282a9cbe508f..25e2493abc6a 100644 --- a/drivers/infiniband/hw/nes/nes_cm.h +++ b/drivers/infiniband/hw/nes/nes_cm.h | |||
@@ -76,6 +76,10 @@ enum nes_timer_type { | |||
76 | NES_TIMER_TYPE_CLOSE, | 76 | NES_TIMER_TYPE_CLOSE, |
77 | }; | 77 | }; |
78 | 78 | ||
79 | #define NES_PASSIVE_STATE_INDICATED 0 | ||
80 | #define NES_DO_NOT_SEND_RESET_EVENT 1 | ||
81 | #define NES_SEND_RESET_EVENT 2 | ||
82 | |||
79 | #define MAX_NES_IFS 4 | 83 | #define MAX_NES_IFS 4 |
80 | 84 | ||
81 | #define SET_ACK 1 | 85 | #define SET_ACK 1 |
@@ -295,6 +299,7 @@ struct nes_cm_node { | |||
295 | struct list_head timer_entry; | 299 | struct list_head timer_entry; |
296 | struct list_head reset_entry; | 300 | struct list_head reset_entry; |
297 | struct nes_qp *nesqp; | 301 | struct nes_qp *nesqp; |
302 | atomic_t passive_state; | ||
298 | }; | 303 | }; |
299 | 304 | ||
300 | /* structure for client or CM to fill when making CM api calls. */ | 305 | /* structure for client or CM to fill when making CM api calls. */ |