diff options
Diffstat (limited to 'net/tipc/node.c')
-rw-r--r-- | net/tipc/node.c | 55 |
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 | ||
53 | struct node *tipc_nodes = NULL; /* sorted list of nodes within cluster */ | 53 | struct node *tipc_nodes = NULL; /* sorted list of nodes within cluster */ |
54 | 54 | ||
55 | static DEFINE_SPINLOCK(node_create_lock); | ||
56 | |||
55 | u32 tipc_own_tag = 0; | 57 | u32 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 | |||
57 | struct node *tipc_node_create(u32 addr) | 69 | struct 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 | } |