aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/node.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/tipc/node.c')
-rw-r--r--net/tipc/node.c55
1 files changed, 50 insertions, 5 deletions
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 598f4d3a0098..ee952ad60218 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -52,16 +52,40 @@ static void node_established_contact(struct node *n_ptr);
52 52
53struct node *tipc_nodes = NULL; /* sorted list of nodes within cluster */ 53struct node *tipc_nodes = NULL; /* sorted list of nodes within cluster */
54 54
55static DEFINE_SPINLOCK(node_create_lock);
56
55u32 tipc_own_tag = 0; 57u32 tipc_own_tag = 0;
56 58
59/**
60 * tipc_node_create - create neighboring node
61 *
62 * Currently, this routine is called by neighbor discovery code, which holds
63 * net_lock for reading only. We must take node_create_lock to ensure a node
64 * isn't created twice if two different bearers discover the node at the same
65 * time. (It would be preferable to switch to holding net_lock in write mode,
66 * but this is a non-trivial change.)
67 */
68
57struct node *tipc_node_create(u32 addr) 69struct node *tipc_node_create(u32 addr)
58{ 70{
59 struct cluster *c_ptr; 71 struct cluster *c_ptr;
60 struct node *n_ptr; 72 struct node *n_ptr;
61 struct node **curr_node; 73 struct node **curr_node;
62 74
75 spin_lock_bh(&node_create_lock);
76
77 for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
78 if (addr < n_ptr->addr)
79 break;
80 if (addr == n_ptr->addr) {
81 spin_unlock_bh(&node_create_lock);
82 return n_ptr;
83 }
84 }
85
63 n_ptr = kzalloc(sizeof(*n_ptr),GFP_ATOMIC); 86 n_ptr = kzalloc(sizeof(*n_ptr),GFP_ATOMIC);
64 if (!n_ptr) { 87 if (!n_ptr) {
88 spin_unlock_bh(&node_create_lock);
65 warn("Node creation failed, no memory\n"); 89 warn("Node creation failed, no memory\n");
66 return NULL; 90 return NULL;
67 } 91 }
@@ -71,6 +95,7 @@ struct node *tipc_node_create(u32 addr)
71 c_ptr = tipc_cltr_create(addr); 95 c_ptr = tipc_cltr_create(addr);
72 } 96 }
73 if (!c_ptr) { 97 if (!c_ptr) {
98 spin_unlock_bh(&node_create_lock);
74 kfree(n_ptr); 99 kfree(n_ptr);
75 return NULL; 100 return NULL;
76 } 101 }
@@ -91,6 +116,7 @@ struct node *tipc_node_create(u32 addr)
91 } 116 }
92 } 117 }
93 (*curr_node) = n_ptr; 118 (*curr_node) = n_ptr;
119 spin_unlock_bh(&node_create_lock);
94 return n_ptr; 120 return n_ptr;
95} 121}
96 122
@@ -574,12 +600,14 @@ u32 tipc_available_nodes(const u32 domain)
574 struct node *n_ptr; 600 struct node *n_ptr;
575 u32 cnt = 0; 601 u32 cnt = 0;
576 602
603 read_lock_bh(&tipc_net_lock);
577 for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) { 604 for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
578 if (!in_scope(domain, n_ptr->addr)) 605 if (!in_scope(domain, n_ptr->addr))
579 continue; 606 continue;
580 if (tipc_node_is_up(n_ptr)) 607 if (tipc_node_is_up(n_ptr))
581 cnt++; 608 cnt++;
582 } 609 }
610 read_unlock_bh(&tipc_net_lock);
583 return cnt; 611 return cnt;
584} 612}
585 613
@@ -599,19 +627,26 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
599 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 627 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
600 " (network address)"); 628 " (network address)");
601 629
602 if (!tipc_nodes) 630 read_lock_bh(&tipc_net_lock);
631 if (!tipc_nodes) {
632 read_unlock_bh(&tipc_net_lock);
603 return tipc_cfg_reply_none(); 633 return tipc_cfg_reply_none();
634 }
604 635
605 /* For now, get space for all other nodes 636 /* For now, get space for all other nodes
606 (will need to modify this when slave nodes are supported */ 637 (will need to modify this when slave nodes are supported */
607 638
608 payload_size = TLV_SPACE(sizeof(node_info)) * (tipc_max_nodes - 1); 639 payload_size = TLV_SPACE(sizeof(node_info)) * (tipc_max_nodes - 1);
609 if (payload_size > 32768u) 640 if (payload_size > 32768u) {
641 read_unlock_bh(&tipc_net_lock);
610 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 642 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
611 " (too many nodes)"); 643 " (too many nodes)");
644 }
612 buf = tipc_cfg_reply_alloc(payload_size); 645 buf = tipc_cfg_reply_alloc(payload_size);
613 if (!buf) 646 if (!buf) {
647 read_unlock_bh(&tipc_net_lock);
614 return NULL; 648 return NULL;
649 }
615 650
616 /* Add TLVs for all nodes in scope */ 651 /* Add TLVs for all nodes in scope */
617 652
@@ -624,6 +659,7 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
624 &node_info, sizeof(node_info)); 659 &node_info, sizeof(node_info));
625 } 660 }
626 661
662 read_unlock_bh(&tipc_net_lock);
627 return buf; 663 return buf;
628} 664}
629 665
@@ -646,16 +682,22 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
646 if (tipc_mode != TIPC_NET_MODE) 682 if (tipc_mode != TIPC_NET_MODE)
647 return tipc_cfg_reply_none(); 683 return tipc_cfg_reply_none();
648 684
685 read_lock_bh(&tipc_net_lock);
686
649 /* Get space for all unicast links + multicast link */ 687 /* Get space for all unicast links + multicast link */
650 688
651 payload_size = TLV_SPACE(sizeof(link_info)) * 689 payload_size = TLV_SPACE(sizeof(link_info)) *
652 (tipc_net.zones[tipc_zone(tipc_own_addr)]->links + 1); 690 (tipc_net.zones[tipc_zone(tipc_own_addr)]->links + 1);
653 if (payload_size > 32768u) 691 if (payload_size > 32768u) {
692 read_unlock_bh(&tipc_net_lock);
654 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 693 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
655 " (too many links)"); 694 " (too many links)");
695 }
656 buf = tipc_cfg_reply_alloc(payload_size); 696 buf = tipc_cfg_reply_alloc(payload_size);
657 if (!buf) 697 if (!buf) {
698 read_unlock_bh(&tipc_net_lock);
658 return NULL; 699 return NULL;
700 }
659 701
660 /* Add TLV for broadcast link */ 702 /* Add TLV for broadcast link */
661 703
@@ -671,6 +713,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
671 713
672 if (!in_scope(domain, n_ptr->addr)) 714 if (!in_scope(domain, n_ptr->addr))
673 continue; 715 continue;
716 tipc_node_lock(n_ptr);
674 for (i = 0; i < MAX_BEARERS; i++) { 717 for (i = 0; i < MAX_BEARERS; i++) {
675 if (!n_ptr->links[i]) 718 if (!n_ptr->links[i])
676 continue; 719 continue;
@@ -680,7 +723,9 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
680 tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, 723 tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO,
681 &link_info, sizeof(link_info)); 724 &link_info, sizeof(link_info));
682 } 725 }
726 tipc_node_unlock(n_ptr);
683 } 727 }
684 728
729 read_unlock_bh(&tipc_net_lock);
685 return buf; 730 return buf;
686} 731}