aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw
diff options
context:
space:
mode:
authorFaisal Latif <faisal.latif@intel.com>2008-11-21 21:50:41 -0500
committerRoland Dreier <rolandd@cisco.com>2008-12-05 14:00:02 -0500
commit879e5bd5a1a0a317fb67fa4dc550db092a7bdcb0 (patch)
tree220e3f3d077f123032d13253aa6cc8570b549917 /drivers/infiniband/hw
parentc5d321e5c924384cf5b35f6288d69e9237490565 (diff)
RDMA/nes: Lock down connected_nodes list while processing it
While processing connected_nodes list, we would release the lock when we need to send reset to remote partner. That created a window where the list can be modified. Change this into a two step process: place nodes that need processing on a local list then process the local list. 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/hw')
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c40
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.h2
2 files changed, 30 insertions, 12 deletions
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 2a1d6c7f8d32..257d994ec7b5 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -459,13 +459,23 @@ static void nes_cm_timer_tick(unsigned long pass)
459 int ret = NETDEV_TX_OK; 459 int ret = NETDEV_TX_OK;
460 enum nes_cm_node_state last_state; 460 enum nes_cm_node_state last_state;
461 461
462 struct list_head timer_list;
463 INIT_LIST_HEAD(&timer_list);
462 spin_lock_irqsave(&cm_core->ht_lock, flags); 464 spin_lock_irqsave(&cm_core->ht_lock, flags);
463 465
464 list_for_each_safe(list_node, list_core_temp, 466 list_for_each_safe(list_node, list_core_temp,
465 &cm_core->connected_nodes) { 467 &cm_core->connected_nodes) {
466 cm_node = container_of(list_node, struct nes_cm_node, list); 468 cm_node = container_of(list_node, struct nes_cm_node, list);
467 add_ref_cm_node(cm_node); 469 if (!list_empty(&cm_node->recv_list) || (cm_node->send_entry)) {
468 spin_unlock_irqrestore(&cm_core->ht_lock, flags); 470 add_ref_cm_node(cm_node);
471 list_add(&cm_node->timer_entry, &timer_list);
472 }
473 }
474 spin_unlock_irqrestore(&cm_core->ht_lock, flags);
475
476 list_for_each_safe(list_node, list_core_temp, &timer_list) {
477 cm_node = container_of(list_node, struct nes_cm_node,
478 timer_entry);
469 spin_lock_irqsave(&cm_node->recv_list_lock, flags); 479 spin_lock_irqsave(&cm_node->recv_list_lock, flags);
470 list_for_each_safe(list_core, list_node_temp, 480 list_for_each_safe(list_core, list_node_temp,
471 &cm_node->recv_list) { 481 &cm_node->recv_list) {
@@ -615,14 +625,12 @@ static void nes_cm_timer_tick(unsigned long pass)
615 625
616 spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); 626 spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
617 rem_ref_cm_node(cm_node->cm_core, cm_node); 627 rem_ref_cm_node(cm_node->cm_core, cm_node);
618 spin_lock_irqsave(&cm_core->ht_lock, flags);
619 if (ret != NETDEV_TX_OK) { 628 if (ret != NETDEV_TX_OK) {
620 nes_debug(NES_DBG_CM, "rexmit failed for cm_node=%p\n", 629 nes_debug(NES_DBG_CM, "rexmit failed for cm_node=%p\n",
621 cm_node); 630 cm_node);
622 break; 631 break;
623 } 632 }
624 } 633 }
625 spin_unlock_irqrestore(&cm_core->ht_lock, flags);
626 634
627 if (settimer) { 635 if (settimer) {
628 if (!timer_pending(&cm_core->tcp_timer)) { 636 if (!timer_pending(&cm_core->tcp_timer)) {
@@ -925,28 +933,36 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
925 struct list_head *list_pos = NULL; 933 struct list_head *list_pos = NULL;
926 struct list_head *list_temp = NULL; 934 struct list_head *list_temp = NULL;
927 struct nes_cm_node *cm_node = NULL; 935 struct nes_cm_node *cm_node = NULL;
936 struct list_head reset_list;
928 937
929 nes_debug(NES_DBG_CM, "attempting listener= %p free_nodes= %d, " 938 nes_debug(NES_DBG_CM, "attempting listener= %p free_nodes= %d, "
930 "refcnt=%d\n", listener, free_hanging_nodes, 939 "refcnt=%d\n", listener, free_hanging_nodes,
931 atomic_read(&listener->ref_count)); 940 atomic_read(&listener->ref_count));
932 /* free non-accelerated child nodes for this listener */ 941 /* free non-accelerated child nodes for this listener */
942 INIT_LIST_HEAD(&reset_list);
933 if (free_hanging_nodes) { 943 if (free_hanging_nodes) {
934 spin_lock_irqsave(&cm_core->ht_lock, flags); 944 spin_lock_irqsave(&cm_core->ht_lock, flags);
935 list_for_each_safe(list_pos, list_temp, 945 list_for_each_safe(list_pos, list_temp,
936 &g_cm_core->connected_nodes) { 946 &g_cm_core->connected_nodes) {
937 cm_node = container_of(list_pos, struct nes_cm_node, 947 cm_node = container_of(list_pos, struct nes_cm_node,
938 list); 948 list);
939 if ((cm_node->listener == listener) && 949 if ((cm_node->listener == listener) &&
940 (!cm_node->accelerated)) { 950 (!cm_node->accelerated)) {
941 cleanup_retrans_entry(cm_node); 951 add_ref_cm_node(cm_node);
942 spin_unlock_irqrestore(&cm_core->ht_lock, 952 list_add(&cm_node->reset_entry, &reset_list);
943 flags);
944 send_reset(cm_node, NULL);
945 spin_lock_irqsave(&cm_core->ht_lock, flags);
946 } 953 }
947 } 954 }
948 spin_unlock_irqrestore(&cm_core->ht_lock, flags); 955 spin_unlock_irqrestore(&cm_core->ht_lock, flags);
949 } 956 }
957
958 list_for_each_safe(list_pos, list_temp, &reset_list) {
959 cm_node = container_of(list_pos, struct nes_cm_node,
960 reset_entry);
961 cleanup_retrans_entry(cm_node);
962 send_reset(cm_node, NULL);
963 rem_ref_cm_node(cm_node->cm_core, cm_node);
964 }
965
950 spin_lock_irqsave(&cm_core->listen_list_lock, flags); 966 spin_lock_irqsave(&cm_core->listen_list_lock, flags);
951 if (!atomic_dec_return(&listener->ref_count)) { 967 if (!atomic_dec_return(&listener->ref_count)) {
952 list_del(&listener->list); 968 list_del(&listener->list);
diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h
index 367b3d290140..282a9cbe508f 100644
--- a/drivers/infiniband/hw/nes/nes_cm.h
+++ b/drivers/infiniband/hw/nes/nes_cm.h
@@ -292,6 +292,8 @@ struct nes_cm_node {
292 int apbvt_set; 292 int apbvt_set;
293 int accept_pend; 293 int accept_pend;
294 int freed; 294 int freed;
295 struct list_head timer_entry;
296 struct list_head reset_entry;
295 struct nes_qp *nesqp; 297 struct nes_qp *nesqp;
296}; 298};
297 299