Merge branch 'devicetree/next' of git://git.secretlab.ca/git/linux-2.6
[cascardo/linux.git] / net / tipc / node.c
index 3af53e3..2d106ef 100644 (file)
@@ -2,7 +2,7 @@
  * net/tipc/node.c: TIPC node management routines
  *
  * Copyright (c) 2000-2006, Ericsson AB
- * Copyright (c) 2005-2006, Wind River Systems
+ * Copyright (c) 2005-2006, 2010-2011, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,8 +44,32 @@ static void node_established_contact(struct tipc_node *n_ptr);
 
 static DEFINE_SPINLOCK(node_create_lock);
 
+static struct hlist_head node_htable[NODE_HTABLE_SIZE];
+LIST_HEAD(tipc_node_list);
+static u32 tipc_num_nodes;
+
+static atomic_t tipc_num_links = ATOMIC_INIT(0);
 u32 tipc_own_tag;
 
+/**
+ * tipc_node_find - locate specified node object, if it exists
+ */
+
+struct tipc_node *tipc_node_find(u32 addr)
+{
+       struct tipc_node *node;
+       struct hlist_node *pos;
+
+       if (unlikely(!in_own_cluster(addr)))
+               return NULL;
+
+       hlist_for_each_entry(node, pos, &node_htable[tipc_hashfn(addr)], hash) {
+               if (node->addr == addr)
+                       return node;
+       }
+       return NULL;
+}
+
 /**
  * tipc_node_create - create neighboring node
  *
@@ -58,8 +82,7 @@ u32 tipc_own_tag;
 
 struct tipc_node *tipc_node_create(u32 addr)
 {
-       struct tipc_node *n_ptr;
-       u32 n_num;
+       struct tipc_node *n_ptr, *temp_node;
 
        spin_lock_bh(&node_create_lock);
 
@@ -78,12 +101,19 @@ struct tipc_node *tipc_node_create(u32 addr)
 
        n_ptr->addr = addr;
        spin_lock_init(&n_ptr->lock);
+       INIT_HLIST_NODE(&n_ptr->hash);
+       INIT_LIST_HEAD(&n_ptr->list);
        INIT_LIST_HEAD(&n_ptr->nsub);
 
-       n_num = tipc_node(addr);
-       tipc_net.nodes[n_num] = n_ptr;
-       if (n_num > tipc_net.highest_node)
-               tipc_net.highest_node = n_num;
+       hlist_add_head(&n_ptr->hash, &node_htable[tipc_hashfn(addr)]);
+
+       list_for_each_entry(temp_node, &tipc_node_list, list) {
+               if (n_ptr->addr < temp_node->addr)
+                       break;
+       }
+       list_add_tail(&n_ptr->list, &temp_node->list);
+
+       tipc_num_nodes++;
 
        spin_unlock_bh(&node_create_lock);
        return n_ptr;
@@ -91,18 +121,11 @@ struct tipc_node *tipc_node_create(u32 addr)
 
 void tipc_node_delete(struct tipc_node *n_ptr)
 {
-       u32 n_num;
-
-       if (!n_ptr)
-               return;
-
-       n_num = tipc_node(n_ptr->addr);
-       tipc_net.nodes[n_num] = NULL;
+       list_del(&n_ptr->list);
+       hlist_del(&n_ptr->hash);
        kfree(n_ptr);
 
-       while (!tipc_net.nodes[tipc_net.highest_node])
-               if (--tipc_net.highest_node == 0)
-                       break;
+       tipc_num_nodes--;
 }
 
 
@@ -200,54 +223,32 @@ void tipc_node_link_down(struct tipc_node *n_ptr, struct link *l_ptr)
                node_lost_contact(n_ptr);
 }
 
-int tipc_node_has_active_links(struct tipc_node *n_ptr)
+int tipc_node_active_links(struct tipc_node *n_ptr)
 {
        return n_ptr->active_links[0] != NULL;
 }
 
-int tipc_node_has_redundant_links(struct tipc_node *n_ptr)
+int tipc_node_redundant_links(struct tipc_node *n_ptr)
 {
        return n_ptr->working_links > 1;
 }
 
 int tipc_node_is_up(struct tipc_node *n_ptr)
 {
-       return tipc_node_has_active_links(n_ptr);
+       return tipc_node_active_links(n_ptr);
 }
 
-struct tipc_node *tipc_node_attach_link(struct link *l_ptr)
+void tipc_node_attach_link(struct tipc_node *n_ptr, struct link *l_ptr)
 {
-       struct tipc_node *n_ptr = tipc_node_find(l_ptr->addr);
-
-       if (!n_ptr)
-               n_ptr = tipc_node_create(l_ptr->addr);
-       if (n_ptr) {
-               u32 bearer_id = l_ptr->b_ptr->identity;
-               char addr_string[16];
-
-               if (n_ptr->link_cnt >= 2) {
-                       err("Attempt to create third link to %s\n",
-                           tipc_addr_string_fill(addr_string, n_ptr->addr));
-                       return NULL;
-               }
-
-               if (!n_ptr->links[bearer_id]) {
-                       n_ptr->links[bearer_id] = l_ptr;
-                       tipc_net.links++;
-                       n_ptr->link_cnt++;
-                       return n_ptr;
-               }
-               err("Attempt to establish second link on <%s> to %s\n",
-                   l_ptr->b_ptr->publ.name,
-                   tipc_addr_string_fill(addr_string, l_ptr->addr));
-       }
-       return NULL;
+       n_ptr->links[l_ptr->b_ptr->identity] = l_ptr;
+       atomic_inc(&tipc_num_links);
+       n_ptr->link_cnt++;
 }
 
 void tipc_node_detach_link(struct tipc_node *n_ptr, struct link *l_ptr)
 {
        n_ptr->links[l_ptr->b_ptr->identity] = NULL;
-       tipc_net.links--;
+       atomic_dec(&tipc_num_links);
        n_ptr->link_cnt--;
 }
 
@@ -327,7 +328,6 @@ static void node_cleanup_finished(unsigned long node_addr)
 
 static void node_lost_contact(struct tipc_node *n_ptr)
 {
-       struct tipc_node_subscr *ns, *tns;
        char addr_string[16];
        u32 i;
 
@@ -365,12 +365,7 @@ static void node_lost_contact(struct tipc_node *n_ptr)
        }
 
        /* Notify subscribers */
-       list_for_each_entry_safe(ns, tns, &n_ptr->nsub, nodesub_list) {
-               ns->node = NULL;
-               list_del_init(&ns->nodesub_list);
-               tipc_k_signal((Handler)ns->handle_node_down,
-                             (unsigned long)ns->usr_handle);
-       }
+       tipc_nodesub_notify(n_ptr);
 
        /* Prevent re-contact with node until all cleanup is done */
 
@@ -385,7 +380,6 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
        struct tipc_node *n_ptr;
        struct tipc_node_info node_info;
        u32 payload_size;
-       u32 n_num;
 
        if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
                return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
@@ -396,15 +390,14 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
                                                   " (network address)");
 
        read_lock_bh(&tipc_net_lock);
-       if (!tipc_net.nodes) {
+       if (!tipc_num_nodes) {
                read_unlock_bh(&tipc_net_lock);
                return tipc_cfg_reply_none();
        }
 
        /* For now, get space for all other nodes */
 
-       payload_size = TLV_SPACE(sizeof(node_info)) *
-               (tipc_net.highest_node - 1);
+       payload_size = TLV_SPACE(sizeof(node_info)) * tipc_num_nodes;
        if (payload_size > 32768u) {
                read_unlock_bh(&tipc_net_lock);
                return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
@@ -418,9 +411,8 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
 
        /* Add TLVs for all nodes in scope */
 
-       for (n_num = 1; n_num <= tipc_net.highest_node; n_num++) {
-               n_ptr = tipc_net.nodes[n_num];
-               if (!n_ptr || !tipc_in_scope(domain, n_ptr->addr))
+       list_for_each_entry(n_ptr, &tipc_node_list, list) {
+               if (!tipc_in_scope(domain, n_ptr->addr))
                        continue;
                node_info.addr = htonl(n_ptr->addr);
                node_info.up = htonl(tipc_node_is_up(n_ptr));
@@ -439,7 +431,6 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
        struct tipc_node *n_ptr;
        struct tipc_link_info link_info;
        u32 payload_size;
-       u32 n_num;
 
        if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
                return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
@@ -456,7 +447,8 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
 
        /* Get space for all unicast links + multicast link */
 
-       payload_size = TLV_SPACE(sizeof(link_info)) * (tipc_net.links + 1);
+       payload_size = TLV_SPACE(sizeof(link_info)) *
+               (atomic_read(&tipc_num_links) + 1);
        if (payload_size > 32768u) {
                read_unlock_bh(&tipc_net_lock);
                return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
@@ -470,18 +462,17 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
 
        /* Add TLV for broadcast link */
 
-       link_info.dest = htonl(tipc_own_addr & 0xfffff00);
+       link_info.dest = htonl(tipc_cluster_mask(tipc_own_addr));
        link_info.up = htonl(1);
        strlcpy(link_info.str, tipc_bclink_name, TIPC_MAX_LINK_NAME);
        tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info));
 
        /* Add TLVs for any other links in scope */
 
-       for (n_num = 1; n_num <= tipc_net.highest_node; n_num++) {
+       list_for_each_entry(n_ptr, &tipc_node_list, list) {
                u32 i;
 
-               n_ptr = tipc_net.nodes[n_num];
-               if (!n_ptr || !tipc_in_scope(domain, n_ptr->addr))
+               if (!tipc_in_scope(domain, n_ptr->addr))
                        continue;
                tipc_node_lock(n_ptr);
                for (i = 0; i < MAX_BEARERS; i++) {