diff options
Diffstat (limited to 'net/tipc/node.c')
| -rw-r--r-- | net/tipc/node.c | 125 |
1 files changed, 58 insertions, 67 deletions
diff --git a/net/tipc/node.c b/net/tipc/node.c index 3af53e327f49..2d106ef4fa4c 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * net/tipc/node.c: TIPC node management routines | 2 | * net/tipc/node.c: TIPC node management routines |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2000-2006, Ericsson AB | 4 | * Copyright (c) 2000-2006, Ericsson AB |
| 5 | * Copyright (c) 2005-2006, Wind River Systems | 5 | * Copyright (c) 2005-2006, 2010-2011, Wind River Systems |
| 6 | * All rights reserved. | 6 | * All rights reserved. |
| 7 | * | 7 | * |
| 8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without |
| @@ -44,9 +44,33 @@ static void node_established_contact(struct tipc_node *n_ptr); | |||
| 44 | 44 | ||
| 45 | static DEFINE_SPINLOCK(node_create_lock); | 45 | static DEFINE_SPINLOCK(node_create_lock); |
| 46 | 46 | ||
| 47 | static struct hlist_head node_htable[NODE_HTABLE_SIZE]; | ||
| 48 | LIST_HEAD(tipc_node_list); | ||
| 49 | static u32 tipc_num_nodes; | ||
| 50 | |||
| 51 | static atomic_t tipc_num_links = ATOMIC_INIT(0); | ||
| 47 | u32 tipc_own_tag; | 52 | u32 tipc_own_tag; |
| 48 | 53 | ||
| 49 | /** | 54 | /** |
| 55 | * tipc_node_find - locate specified node object, if it exists | ||
| 56 | */ | ||
| 57 | |||
| 58 | struct tipc_node *tipc_node_find(u32 addr) | ||
| 59 | { | ||
| 60 | struct tipc_node *node; | ||
| 61 | struct hlist_node *pos; | ||
| 62 | |||
| 63 | if (unlikely(!in_own_cluster(addr))) | ||
| 64 | return NULL; | ||
| 65 | |||
| 66 | hlist_for_each_entry(node, pos, &node_htable[tipc_hashfn(addr)], hash) { | ||
| 67 | if (node->addr == addr) | ||
| 68 | return node; | ||
| 69 | } | ||
| 70 | return NULL; | ||
| 71 | } | ||
| 72 | |||
| 73 | /** | ||
| 50 | * tipc_node_create - create neighboring node | 74 | * tipc_node_create - create neighboring node |
| 51 | * | 75 | * |
| 52 | * Currently, this routine is called by neighbor discovery code, which holds | 76 | * Currently, this routine is called by neighbor discovery code, which holds |
| @@ -58,8 +82,7 @@ u32 tipc_own_tag; | |||
| 58 | 82 | ||
| 59 | struct tipc_node *tipc_node_create(u32 addr) | 83 | struct tipc_node *tipc_node_create(u32 addr) |
| 60 | { | 84 | { |
| 61 | struct tipc_node *n_ptr; | 85 | struct tipc_node *n_ptr, *temp_node; |
| 62 | u32 n_num; | ||
| 63 | 86 | ||
| 64 | spin_lock_bh(&node_create_lock); | 87 | spin_lock_bh(&node_create_lock); |
| 65 | 88 | ||
| @@ -78,12 +101,19 @@ struct tipc_node *tipc_node_create(u32 addr) | |||
| 78 | 101 | ||
| 79 | n_ptr->addr = addr; | 102 | n_ptr->addr = addr; |
| 80 | spin_lock_init(&n_ptr->lock); | 103 | spin_lock_init(&n_ptr->lock); |
| 104 | INIT_HLIST_NODE(&n_ptr->hash); | ||
| 105 | INIT_LIST_HEAD(&n_ptr->list); | ||
| 81 | INIT_LIST_HEAD(&n_ptr->nsub); | 106 | INIT_LIST_HEAD(&n_ptr->nsub); |
| 82 | 107 | ||
| 83 | n_num = tipc_node(addr); | 108 | hlist_add_head(&n_ptr->hash, &node_htable[tipc_hashfn(addr)]); |
| 84 | tipc_net.nodes[n_num] = n_ptr; | 109 | |
| 85 | if (n_num > tipc_net.highest_node) | 110 | list_for_each_entry(temp_node, &tipc_node_list, list) { |
| 86 | tipc_net.highest_node = n_num; | 111 | if (n_ptr->addr < temp_node->addr) |
| 112 | break; | ||
| 113 | } | ||
| 114 | list_add_tail(&n_ptr->list, &temp_node->list); | ||
| 115 | |||
| 116 | tipc_num_nodes++; | ||
| 87 | 117 | ||
| 88 | spin_unlock_bh(&node_create_lock); | 118 | spin_unlock_bh(&node_create_lock); |
| 89 | return n_ptr; | 119 | return n_ptr; |
| @@ -91,18 +121,11 @@ struct tipc_node *tipc_node_create(u32 addr) | |||
| 91 | 121 | ||
| 92 | void tipc_node_delete(struct tipc_node *n_ptr) | 122 | void tipc_node_delete(struct tipc_node *n_ptr) |
| 93 | { | 123 | { |
| 94 | u32 n_num; | 124 | list_del(&n_ptr->list); |
| 95 | 125 | hlist_del(&n_ptr->hash); | |
| 96 | if (!n_ptr) | ||
| 97 | return; | ||
| 98 | |||
| 99 | n_num = tipc_node(n_ptr->addr); | ||
| 100 | tipc_net.nodes[n_num] = NULL; | ||
| 101 | kfree(n_ptr); | 126 | kfree(n_ptr); |
| 102 | 127 | ||
| 103 | while (!tipc_net.nodes[tipc_net.highest_node]) | 128 | tipc_num_nodes--; |
| 104 | if (--tipc_net.highest_node == 0) | ||
| 105 | break; | ||
| 106 | } | 129 | } |
| 107 | 130 | ||
| 108 | 131 | ||
| @@ -200,54 +223,32 @@ void tipc_node_link_down(struct tipc_node *n_ptr, struct link *l_ptr) | |||
| 200 | node_lost_contact(n_ptr); | 223 | node_lost_contact(n_ptr); |
| 201 | } | 224 | } |
| 202 | 225 | ||
| 203 | int tipc_node_has_active_links(struct tipc_node *n_ptr) | 226 | int tipc_node_active_links(struct tipc_node *n_ptr) |
| 204 | { | 227 | { |
| 205 | return n_ptr->active_links[0] != NULL; | 228 | return n_ptr->active_links[0] != NULL; |
| 206 | } | 229 | } |
| 207 | 230 | ||
| 208 | int tipc_node_has_redundant_links(struct tipc_node *n_ptr) | 231 | int tipc_node_redundant_links(struct tipc_node *n_ptr) |
| 209 | { | 232 | { |
| 210 | return n_ptr->working_links > 1; | 233 | return n_ptr->working_links > 1; |
| 211 | } | 234 | } |
| 212 | 235 | ||
| 213 | int tipc_node_is_up(struct tipc_node *n_ptr) | 236 | int tipc_node_is_up(struct tipc_node *n_ptr) |
| 214 | { | 237 | { |
| 215 | return tipc_node_has_active_links(n_ptr); | 238 | return tipc_node_active_links(n_ptr); |
| 216 | } | 239 | } |
| 217 | 240 | ||
| 218 | struct tipc_node *tipc_node_attach_link(struct link *l_ptr) | 241 | void tipc_node_attach_link(struct tipc_node *n_ptr, struct link *l_ptr) |
| 219 | { | 242 | { |
| 220 | struct tipc_node *n_ptr = tipc_node_find(l_ptr->addr); | 243 | n_ptr->links[l_ptr->b_ptr->identity] = l_ptr; |
| 221 | 244 | atomic_inc(&tipc_num_links); | |
| 222 | if (!n_ptr) | 245 | n_ptr->link_cnt++; |
| 223 | n_ptr = tipc_node_create(l_ptr->addr); | ||
| 224 | if (n_ptr) { | ||
| 225 | u32 bearer_id = l_ptr->b_ptr->identity; | ||
| 226 | char addr_string[16]; | ||
| 227 | |||
| 228 | if (n_ptr->link_cnt >= 2) { | ||
| 229 | err("Attempt to create third link to %s\n", | ||
| 230 | tipc_addr_string_fill(addr_string, n_ptr->addr)); | ||
| 231 | return NULL; | ||
| 232 | } | ||
| 233 | |||
| 234 | if (!n_ptr->links[bearer_id]) { | ||
| 235 | n_ptr->links[bearer_id] = l_ptr; | ||
| 236 | tipc_net.links++; | ||
| 237 | n_ptr->link_cnt++; | ||
| 238 | return n_ptr; | ||
| 239 | } | ||
| 240 | err("Attempt to establish second link on <%s> to %s\n", | ||
| 241 | l_ptr->b_ptr->publ.name, | ||
| 242 | tipc_addr_string_fill(addr_string, l_ptr->addr)); | ||
| 243 | } | ||
| 244 | return NULL; | ||
| 245 | } | 246 | } |
| 246 | 247 | ||
| 247 | void tipc_node_detach_link(struct tipc_node *n_ptr, struct link *l_ptr) | 248 | void tipc_node_detach_link(struct tipc_node *n_ptr, struct link *l_ptr) |
| 248 | { | 249 | { |
| 249 | n_ptr->links[l_ptr->b_ptr->identity] = NULL; | 250 | n_ptr->links[l_ptr->b_ptr->identity] = NULL; |
| 250 | tipc_net.links--; | 251 | atomic_dec(&tipc_num_links); |
| 251 | n_ptr->link_cnt--; | 252 | n_ptr->link_cnt--; |
| 252 | } | 253 | } |
| 253 | 254 | ||
| @@ -327,7 +328,6 @@ static void node_cleanup_finished(unsigned long node_addr) | |||
| 327 | 328 | ||
| 328 | static void node_lost_contact(struct tipc_node *n_ptr) | 329 | static void node_lost_contact(struct tipc_node *n_ptr) |
| 329 | { | 330 | { |
| 330 | struct tipc_node_subscr *ns, *tns; | ||
| 331 | char addr_string[16]; | 331 | char addr_string[16]; |
| 332 | u32 i; | 332 | u32 i; |
| 333 | 333 | ||
| @@ -365,12 +365,7 @@ static void node_lost_contact(struct tipc_node *n_ptr) | |||
| 365 | } | 365 | } |
| 366 | 366 | ||
| 367 | /* Notify subscribers */ | 367 | /* Notify subscribers */ |
| 368 | list_for_each_entry_safe(ns, tns, &n_ptr->nsub, nodesub_list) { | 368 | tipc_nodesub_notify(n_ptr); |
| 369 | ns->node = NULL; | ||
| 370 | list_del_init(&ns->nodesub_list); | ||
| 371 | tipc_k_signal((Handler)ns->handle_node_down, | ||
| 372 | (unsigned long)ns->usr_handle); | ||
| 373 | } | ||
| 374 | 369 | ||
| 375 | /* Prevent re-contact with node until all cleanup is done */ | 370 | /* Prevent re-contact with node until all cleanup is done */ |
| 376 | 371 | ||
| @@ -385,7 +380,6 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space) | |||
| 385 | struct tipc_node *n_ptr; | 380 | struct tipc_node *n_ptr; |
| 386 | struct tipc_node_info node_info; | 381 | struct tipc_node_info node_info; |
| 387 | u32 payload_size; | 382 | u32 payload_size; |
| 388 | u32 n_num; | ||
| 389 | 383 | ||
| 390 | if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) | 384 | if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) |
| 391 | return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); | 385 | 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) | |||
| 396 | " (network address)"); | 390 | " (network address)"); |
| 397 | 391 | ||
| 398 | read_lock_bh(&tipc_net_lock); | 392 | read_lock_bh(&tipc_net_lock); |
| 399 | if (!tipc_net.nodes) { | 393 | if (!tipc_num_nodes) { |
| 400 | read_unlock_bh(&tipc_net_lock); | 394 | read_unlock_bh(&tipc_net_lock); |
| 401 | return tipc_cfg_reply_none(); | 395 | return tipc_cfg_reply_none(); |
| 402 | } | 396 | } |
| 403 | 397 | ||
| 404 | /* For now, get space for all other nodes */ | 398 | /* For now, get space for all other nodes */ |
| 405 | 399 | ||
| 406 | payload_size = TLV_SPACE(sizeof(node_info)) * | 400 | payload_size = TLV_SPACE(sizeof(node_info)) * tipc_num_nodes; |
| 407 | (tipc_net.highest_node - 1); | ||
| 408 | if (payload_size > 32768u) { | 401 | if (payload_size > 32768u) { |
| 409 | read_unlock_bh(&tipc_net_lock); | 402 | read_unlock_bh(&tipc_net_lock); |
| 410 | return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED | 403 | 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) | |||
| 418 | 411 | ||
| 419 | /* Add TLVs for all nodes in scope */ | 412 | /* Add TLVs for all nodes in scope */ |
| 420 | 413 | ||
| 421 | for (n_num = 1; n_num <= tipc_net.highest_node; n_num++) { | 414 | list_for_each_entry(n_ptr, &tipc_node_list, list) { |
| 422 | n_ptr = tipc_net.nodes[n_num]; | 415 | if (!tipc_in_scope(domain, n_ptr->addr)) |
| 423 | if (!n_ptr || !tipc_in_scope(domain, n_ptr->addr)) | ||
| 424 | continue; | 416 | continue; |
| 425 | node_info.addr = htonl(n_ptr->addr); | 417 | node_info.addr = htonl(n_ptr->addr); |
| 426 | node_info.up = htonl(tipc_node_is_up(n_ptr)); | 418 | 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) | |||
| 439 | struct tipc_node *n_ptr; | 431 | struct tipc_node *n_ptr; |
| 440 | struct tipc_link_info link_info; | 432 | struct tipc_link_info link_info; |
| 441 | u32 payload_size; | 433 | u32 payload_size; |
| 442 | u32 n_num; | ||
| 443 | 434 | ||
| 444 | if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) | 435 | if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) |
| 445 | return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); | 436 | 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) | |||
| 456 | 447 | ||
| 457 | /* Get space for all unicast links + multicast link */ | 448 | /* Get space for all unicast links + multicast link */ |
| 458 | 449 | ||
| 459 | payload_size = TLV_SPACE(sizeof(link_info)) * (tipc_net.links + 1); | 450 | payload_size = TLV_SPACE(sizeof(link_info)) * |
| 451 | (atomic_read(&tipc_num_links) + 1); | ||
| 460 | if (payload_size > 32768u) { | 452 | if (payload_size > 32768u) { |
| 461 | read_unlock_bh(&tipc_net_lock); | 453 | read_unlock_bh(&tipc_net_lock); |
| 462 | return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED | 454 | 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) | |||
| 470 | 462 | ||
| 471 | /* Add TLV for broadcast link */ | 463 | /* Add TLV for broadcast link */ |
| 472 | 464 | ||
| 473 | link_info.dest = htonl(tipc_own_addr & 0xfffff00); | 465 | link_info.dest = htonl(tipc_cluster_mask(tipc_own_addr)); |
| 474 | link_info.up = htonl(1); | 466 | link_info.up = htonl(1); |
| 475 | strlcpy(link_info.str, tipc_bclink_name, TIPC_MAX_LINK_NAME); | 467 | strlcpy(link_info.str, tipc_bclink_name, TIPC_MAX_LINK_NAME); |
| 476 | tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info)); | 468 | tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info)); |
| 477 | 469 | ||
| 478 | /* Add TLVs for any other links in scope */ | 470 | /* Add TLVs for any other links in scope */ |
| 479 | 471 | ||
| 480 | for (n_num = 1; n_num <= tipc_net.highest_node; n_num++) { | 472 | list_for_each_entry(n_ptr, &tipc_node_list, list) { |
| 481 | u32 i; | 473 | u32 i; |
| 482 | 474 | ||
| 483 | n_ptr = tipc_net.nodes[n_num]; | 475 | if (!tipc_in_scope(domain, n_ptr->addr)) |
| 484 | if (!n_ptr || !tipc_in_scope(domain, n_ptr->addr)) | ||
| 485 | continue; | 476 | continue; |
| 486 | tipc_node_lock(n_ptr); | 477 | tipc_node_lock(n_ptr); |
| 487 | for (i = 0; i < MAX_BEARERS; i++) { | 478 | for (i = 0; i < MAX_BEARERS; i++) { |
