aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/node.c
diff options
context:
space:
mode:
authorJon Paul Maloy <jon.maloy@ericsson.com>2015-10-15 14:52:44 -0400
committerDavid S. Miller <davem@davemloft.net>2015-10-16 02:55:21 -0400
commit73f646cec35477b5099d7e952297cb9e1855be45 (patch)
tree91356371025167120e9919cc25d806523da367f6 /net/tipc/node.c
parent8306f99a517b91ebf8fa94d017c2c84ca62e107c (diff)
tipc: delay ESTABLISH state event when link is established
Link establishing, just like link teardown, is a non-atomic action, in the sense that discovering that conditions are right to establish a link, and the actual adding of the link to one of the node's send slots is done in two different lock contexts. The link FSM is designed to help bridging the gap between the two contexts in a safe manner. We have now discovered a weakness in the implementaton of this FSM. Because we directly let the link go from state LINK_ESTABLISHING to state LINK_ESTABLISHED already in the first lock context, we are unable to distinguish between a fully established link, i.e., a link that has been added to its slot, and a link that has not yet reached the second lock context. It may hence happen that a manual intervention, e.g., when disabling an interface, causes the function tipc_node_link_down() to try removing the link from the node slots, decrementing its active link counter etc, although the link was never added there in the first place. We solve this by delaying the actual state change until we reach the second lock context, inside the function tipc_node_link_up(). This makes it possible for potentail callers of __tipc_node_link_down() to know if they should proceed or not, and the problem is solved. Unforunately, the situation described above also has a second problem. Since there by necessity is a tipc_node_link_up() call pending once the node lock has been released, we must defuse that call by setting the link back from LINK_ESTABLISHING to LINK_RESET state. This forces us to make a slight modification to the link FSM, which will now look as follows. +------------------------------------+ |RESET_EVT | | | | +--------------+ | +-----------------| SYNCHING |-----------------+ | |FAILURE_EVT +--------------+ PEER_RESET_EVT| | | A | | | | | | | | | | | | | | |SYNCH_ |SYNCH_ | | | |BEGIN_EVT |END_EVT | | | | | | | V | V V | +-------------+ +--------------+ +------------+ | | RESETTING |<---------| ESTABLISHED |--------->| PEER_RESET | | +-------------+ FAILURE_ +--------------+ PEER_ +------------+ | | EVT | A RESET_EVT | | | | | | | | +----------------+ | | | RESET_EVT| |RESET_EVT | | | | | | | | | | |ESTABLISH_EVT | | | | +-------------+ | | | | | | RESET_EVT | | | | | | | | | | | V V V | | | | +-------------+ +--------------+ RESET_EVT| +--->| RESET |--------->| ESTABLISHING |<----------------+ +-------------+ PEER_ +--------------+ | A RESET_EVT | | | | | | | |FAILOVER_ |FAILOVER_ |FAILOVER_ |BEGIN_EVT |END_EVT |BEGIN_EVT | | | V | | +-------------+ | | FAILINGOVER |<----------------+ +-------------+ Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Acked-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/node.c')
-rw-r--r--net/tipc/node.c31
1 files changed, 22 insertions, 9 deletions
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 703875fd6cde..656b5791f1a5 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -317,7 +317,11 @@ static void __tipc_node_link_up(struct tipc_node *n, int bearer_id,
317 struct tipc_link *ol = node_active_link(n, 0); 317 struct tipc_link *ol = node_active_link(n, 0);
318 struct tipc_link *nl = n->links[bearer_id].link; 318 struct tipc_link *nl = n->links[bearer_id].link;
319 319
320 if (!nl || !tipc_link_is_up(nl)) 320 if (!nl)
321 return;
322
323 tipc_link_fsm_evt(nl, LINK_ESTABLISH_EVT);
324 if (!tipc_link_is_up(nl))
321 return; 325 return;
322 326
323 n->working_links++; 327 n->working_links++;
@@ -437,17 +441,26 @@ static void __tipc_node_link_down(struct tipc_node *n, int *bearer_id,
437static void tipc_node_link_down(struct tipc_node *n, int bearer_id, bool delete) 441static void tipc_node_link_down(struct tipc_node *n, int bearer_id, bool delete)
438{ 442{
439 struct tipc_link_entry *le = &n->links[bearer_id]; 443 struct tipc_link_entry *le = &n->links[bearer_id];
444 struct tipc_link *l = le->link;
440 struct tipc_media_addr *maddr; 445 struct tipc_media_addr *maddr;
441 struct sk_buff_head xmitq; 446 struct sk_buff_head xmitq;
442 447
448 if (!l)
449 return;
450
443 __skb_queue_head_init(&xmitq); 451 __skb_queue_head_init(&xmitq);
444 452
445 tipc_node_lock(n); 453 tipc_node_lock(n);
446 __tipc_node_link_down(n, &bearer_id, &xmitq, &maddr); 454 if (!tipc_link_is_establishing(l)) {
447 if (delete && le->link) { 455 __tipc_node_link_down(n, &bearer_id, &xmitq, &maddr);
448 kfree(le->link); 456 if (delete) {
449 le->link = NULL; 457 kfree(l);
450 n->link_cnt--; 458 le->link = NULL;
459 n->link_cnt--;
460 }
461 } else {
462 /* Defuse pending tipc_node_link_up() */
463 tipc_link_fsm_evt(l, LINK_RESET_EVT);
451 } 464 }
452 tipc_node_unlock(n); 465 tipc_node_unlock(n);
453 466
@@ -579,7 +592,7 @@ void tipc_node_check_dest(struct net *net, u32 onode,
579 memcpy(&le->maddr, maddr, sizeof(*maddr)); 592 memcpy(&le->maddr, maddr, sizeof(*maddr));
580exit: 593exit:
581 tipc_node_unlock(n); 594 tipc_node_unlock(n);
582 if (reset) 595 if (reset && !tipc_link_is_reset(l))
583 tipc_node_link_down(n, b->identity, false); 596 tipc_node_link_down(n, b->identity, false);
584 tipc_node_put(n); 597 tipc_node_put(n);
585} 598}
@@ -686,10 +699,10 @@ static void tipc_node_fsm_evt(struct tipc_node *n, int evt)
686 break; 699 break;
687 case SELF_ESTABL_CONTACT_EVT: 700 case SELF_ESTABL_CONTACT_EVT:
688 case PEER_LOST_CONTACT_EVT: 701 case PEER_LOST_CONTACT_EVT:
689 break;
690 case NODE_SYNCH_END_EVT: 702 case NODE_SYNCH_END_EVT:
691 case NODE_SYNCH_BEGIN_EVT:
692 case NODE_FAILOVER_BEGIN_EVT: 703 case NODE_FAILOVER_BEGIN_EVT:
704 break;
705 case NODE_SYNCH_BEGIN_EVT:
693 case NODE_FAILOVER_END_EVT: 706 case NODE_FAILOVER_END_EVT:
694 default: 707 default:
695 goto illegal_evt; 708 goto illegal_evt;