提交 879e5bd5 编写于 作者: F Faisal Latif 提交者: Roland Dreier

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: NFaisal Latif <faisal.latif@intel.com>
Signed-off-by: NChien Tung <chien.tin.tung@intel.com>
Signed-off-by: NRoland Dreier <rolandd@cisco.com>
上级 c5d321e5
...@@ -459,13 +459,23 @@ static void nes_cm_timer_tick(unsigned long pass) ...@@ -459,13 +459,23 @@ static void nes_cm_timer_tick(unsigned long pass)
int ret = NETDEV_TX_OK; int ret = NETDEV_TX_OK;
enum nes_cm_node_state last_state; enum nes_cm_node_state last_state;
struct list_head timer_list;
INIT_LIST_HEAD(&timer_list);
spin_lock_irqsave(&cm_core->ht_lock, flags); spin_lock_irqsave(&cm_core->ht_lock, flags);
list_for_each_safe(list_node, list_core_temp, list_for_each_safe(list_node, list_core_temp,
&cm_core->connected_nodes) { &cm_core->connected_nodes) {
cm_node = container_of(list_node, struct nes_cm_node, list); cm_node = container_of(list_node, struct nes_cm_node, list);
if (!list_empty(&cm_node->recv_list) || (cm_node->send_entry)) {
add_ref_cm_node(cm_node); add_ref_cm_node(cm_node);
list_add(&cm_node->timer_entry, &timer_list);
}
}
spin_unlock_irqrestore(&cm_core->ht_lock, flags); spin_unlock_irqrestore(&cm_core->ht_lock, flags);
list_for_each_safe(list_node, list_core_temp, &timer_list) {
cm_node = container_of(list_node, struct nes_cm_node,
timer_entry);
spin_lock_irqsave(&cm_node->recv_list_lock, flags); spin_lock_irqsave(&cm_node->recv_list_lock, flags);
list_for_each_safe(list_core, list_node_temp, list_for_each_safe(list_core, list_node_temp,
&cm_node->recv_list) { &cm_node->recv_list) {
...@@ -615,14 +625,12 @@ static void nes_cm_timer_tick(unsigned long pass) ...@@ -615,14 +625,12 @@ static void nes_cm_timer_tick(unsigned long pass)
spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
rem_ref_cm_node(cm_node->cm_core, cm_node); rem_ref_cm_node(cm_node->cm_core, cm_node);
spin_lock_irqsave(&cm_core->ht_lock, flags);
if (ret != NETDEV_TX_OK) { if (ret != NETDEV_TX_OK) {
nes_debug(NES_DBG_CM, "rexmit failed for cm_node=%p\n", nes_debug(NES_DBG_CM, "rexmit failed for cm_node=%p\n",
cm_node); cm_node);
break; break;
} }
} }
spin_unlock_irqrestore(&cm_core->ht_lock, flags);
if (settimer) { if (settimer) {
if (!timer_pending(&cm_core->tcp_timer)) { if (!timer_pending(&cm_core->tcp_timer)) {
...@@ -925,11 +933,13 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core, ...@@ -925,11 +933,13 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
struct list_head *list_pos = NULL; struct list_head *list_pos = NULL;
struct list_head *list_temp = NULL; struct list_head *list_temp = NULL;
struct nes_cm_node *cm_node = NULL; struct nes_cm_node *cm_node = NULL;
struct list_head reset_list;
nes_debug(NES_DBG_CM, "attempting listener= %p free_nodes= %d, " nes_debug(NES_DBG_CM, "attempting listener= %p free_nodes= %d, "
"refcnt=%d\n", listener, free_hanging_nodes, "refcnt=%d\n", listener, free_hanging_nodes,
atomic_read(&listener->ref_count)); atomic_read(&listener->ref_count));
/* free non-accelerated child nodes for this listener */ /* free non-accelerated child nodes for this listener */
INIT_LIST_HEAD(&reset_list);
if (free_hanging_nodes) { if (free_hanging_nodes) {
spin_lock_irqsave(&cm_core->ht_lock, flags); spin_lock_irqsave(&cm_core->ht_lock, flags);
list_for_each_safe(list_pos, list_temp, list_for_each_safe(list_pos, list_temp,
...@@ -938,15 +948,21 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core, ...@@ -938,15 +948,21 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
list); list);
if ((cm_node->listener == listener) && if ((cm_node->listener == listener) &&
(!cm_node->accelerated)) { (!cm_node->accelerated)) {
cleanup_retrans_entry(cm_node); add_ref_cm_node(cm_node);
spin_unlock_irqrestore(&cm_core->ht_lock, list_add(&cm_node->reset_entry, &reset_list);
flags);
send_reset(cm_node, NULL);
spin_lock_irqsave(&cm_core->ht_lock, flags);
} }
} }
spin_unlock_irqrestore(&cm_core->ht_lock, flags); spin_unlock_irqrestore(&cm_core->ht_lock, flags);
} }
list_for_each_safe(list_pos, list_temp, &reset_list) {
cm_node = container_of(list_pos, struct nes_cm_node,
reset_entry);
cleanup_retrans_entry(cm_node);
send_reset(cm_node, NULL);
rem_ref_cm_node(cm_node->cm_core, cm_node);
}
spin_lock_irqsave(&cm_core->listen_list_lock, flags); spin_lock_irqsave(&cm_core->listen_list_lock, flags);
if (!atomic_dec_return(&listener->ref_count)) { if (!atomic_dec_return(&listener->ref_count)) {
list_del(&listener->list); list_del(&listener->list);
......
...@@ -292,6 +292,8 @@ struct nes_cm_node { ...@@ -292,6 +292,8 @@ struct nes_cm_node {
int apbvt_set; int apbvt_set;
int accept_pend; int accept_pend;
int freed; int freed;
struct list_head timer_entry;
struct list_head reset_entry;
struct nes_qp *nesqp; struct nes_qp *nesqp;
}; };
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册