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 | } |
