aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
authorJon Paul Maloy <jon.maloy@ericsson.com>2014-02-13 17:29:18 -0500
committerDavid S. Miller <davem@davemloft.net>2014-02-13 17:57:07 -0500
commite099e86c9e24fe9aff36773600543eb31d8954d1 (patch)
tree723936589e12e2bdcbf6aa8b702122b7488cec5e /net/tipc
parenta83045292daf9f07d0b103e5715ef527123d2fcc (diff)
tipc: add node_lock protection to link lookup function
In an earlier commit, ("tipc: remove links list from bearer struct") we described three issues that need to be pre-emptively resolved before we can remove tipc_net_lock. Here we resolve issue a) described in that commit: "a) In access method #2, we access the link before taking the protecting node_lock. This will not work once net_lock is gone, so we will have to change the access order. We will deal with this in a later commit in this series." Here, we change that access order, by ensuring that the function link_find_link() returns only a safe reference for finding the link, i.e., a node pointer and an index into its 'links' array, not the link pointer itself. We also change all callers of this function to first take the node lock before they can check if there still is a valid link pointer at the returned index. Since the function now returns a node pointer rather than a link pointer, we rename it to the more appropriate 'tipc_link_find_owner(). Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Reviewed-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc')
-rw-r--r--net/tipc/link.c110
1 files changed, 65 insertions, 45 deletions
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 03075165665e..4fb4ae0a75ed 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -2390,35 +2390,40 @@ void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window)
2390 l_ptr->queue_limit[MSG_FRAGMENTER] = 4000; 2390 l_ptr->queue_limit[MSG_FRAGMENTER] = 4000;
2391} 2391}
2392 2392
2393/** 2393/* tipc_link_find_owner - locate owner node of link by link's name
2394 * link_find_link - locate link by name 2394 * @name: pointer to link name string
2395 * @name: ptr to link name string 2395 * @bearer_id: pointer to index in 'node->links' array where the link was found.
2396 * @node: ptr to area to be filled with ptr to associated node
2397 *
2398 * Caller must hold 'tipc_net_lock' to ensure node and bearer are not deleted; 2396 * Caller must hold 'tipc_net_lock' to ensure node and bearer are not deleted;
2399 * this also prevents link deletion. 2397 * this also prevents link deletion.
2400 * 2398 *
2401 * Returns pointer to link (or 0 if invalid link name). 2399 * Returns pointer to node owning the link, or 0 if no matching link is found.
2402 */ 2400 */
2403static struct tipc_link *link_find_link(const char *name, 2401static struct tipc_node *tipc_link_find_owner(const char *link_name,
2404 struct tipc_node **node) 2402 unsigned int *bearer_id)
2405{ 2403{
2406 struct tipc_link *l_ptr; 2404 struct tipc_link *l_ptr;
2407 struct tipc_node *n_ptr; 2405 struct tipc_node *n_ptr;
2406 struct tipc_node *tmp_n_ptr;
2407 struct tipc_node *found_node = 0;
2408
2408 int i; 2409 int i;
2409 2410
2410 list_for_each_entry(n_ptr, &tipc_node_list, list) { 2411 *bearer_id = 0;
2412 list_for_each_entry_safe(n_ptr, tmp_n_ptr, &tipc_node_list, list) {
2413 spin_lock(&n_ptr->lock);
2411 for (i = 0; i < MAX_BEARERS; i++) { 2414 for (i = 0; i < MAX_BEARERS; i++) {
2412 l_ptr = n_ptr->links[i]; 2415 l_ptr = n_ptr->links[i];
2413 if (l_ptr && !strcmp(l_ptr->name, name)) 2416 if (l_ptr && !strcmp(l_ptr->name, link_name)) {
2414 goto found; 2417 *bearer_id = i;
2418 found_node = n_ptr;
2419 break;
2420 }
2415 } 2421 }
2422 spin_unlock(&n_ptr->lock);
2423 if (found_node)
2424 break;
2416 } 2425 }
2417 l_ptr = NULL; 2426 return found_node;
2418 n_ptr = NULL;
2419found:
2420 *node = n_ptr;
2421 return l_ptr;
2422} 2427}
2423 2428
2424/** 2429/**
@@ -2460,32 +2465,33 @@ static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd)
2460 struct tipc_link *l_ptr; 2465 struct tipc_link *l_ptr;
2461 struct tipc_bearer *b_ptr; 2466 struct tipc_bearer *b_ptr;
2462 struct tipc_media *m_ptr; 2467 struct tipc_media *m_ptr;
2468 int bearer_id;
2463 int res = 0; 2469 int res = 0;
2464 2470
2465 l_ptr = link_find_link(name, &node); 2471 node = tipc_link_find_owner(name, &bearer_id);
2466 if (l_ptr) { 2472 if (node) {
2467 /*
2468 * acquire node lock for tipc_link_send_proto_msg().
2469 * see "TIPC locking policy" in net.c.
2470 */
2471 tipc_node_lock(node); 2473 tipc_node_lock(node);
2472 switch (cmd) { 2474 l_ptr = node->links[bearer_id];
2473 case TIPC_CMD_SET_LINK_TOL: 2475
2474 link_set_supervision_props(l_ptr, new_value); 2476 if (l_ptr) {
2475 tipc_link_send_proto_msg(l_ptr, 2477 switch (cmd) {
2476 STATE_MSG, 0, 0, new_value, 0, 0); 2478 case TIPC_CMD_SET_LINK_TOL:
2477 break; 2479 link_set_supervision_props(l_ptr, new_value);
2478 case TIPC_CMD_SET_LINK_PRI: 2480 tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0,
2479 l_ptr->priority = new_value; 2481 0, new_value, 0, 0);
2480 tipc_link_send_proto_msg(l_ptr, 2482 break;
2481 STATE_MSG, 0, 0, 0, new_value, 0); 2483 case TIPC_CMD_SET_LINK_PRI:
2482 break; 2484 l_ptr->priority = new_value;
2483 case TIPC_CMD_SET_LINK_WINDOW: 2485 tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0,
2484 tipc_link_set_queue_limits(l_ptr, new_value); 2486 0, 0, new_value, 0);
2485 break; 2487 break;
2486 default: 2488 case TIPC_CMD_SET_LINK_WINDOW:
2487 res = -EINVAL; 2489 tipc_link_set_queue_limits(l_ptr, new_value);
2488 break; 2490 break;
2491 default:
2492 res = -EINVAL;
2493 break;
2494 }
2489 } 2495 }
2490 tipc_node_unlock(node); 2496 tipc_node_unlock(node);
2491 return res; 2497 return res;
@@ -2580,6 +2586,7 @@ struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_
2580 char *link_name; 2586 char *link_name;
2581 struct tipc_link *l_ptr; 2587 struct tipc_link *l_ptr;
2582 struct tipc_node *node; 2588 struct tipc_node *node;
2589 unsigned int bearer_id;
2583 2590
2584 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME)) 2591 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
2585 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 2592 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
@@ -2590,15 +2597,19 @@ struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_
2590 return tipc_cfg_reply_error_string("link not found"); 2597 return tipc_cfg_reply_error_string("link not found");
2591 return tipc_cfg_reply_none(); 2598 return tipc_cfg_reply_none();
2592 } 2599 }
2593
2594 read_lock_bh(&tipc_net_lock); 2600 read_lock_bh(&tipc_net_lock);
2595 l_ptr = link_find_link(link_name, &node); 2601 node = tipc_link_find_owner(link_name, &bearer_id);
2602 if (!node) {
2603 read_unlock_bh(&tipc_net_lock);
2604 return tipc_cfg_reply_error_string("link not found");
2605 }
2606 spin_lock(&node->lock);
2607 l_ptr = node->links[bearer_id];
2596 if (!l_ptr) { 2608 if (!l_ptr) {
2609 tipc_node_unlock(node);
2597 read_unlock_bh(&tipc_net_lock); 2610 read_unlock_bh(&tipc_net_lock);
2598 return tipc_cfg_reply_error_string("link not found"); 2611 return tipc_cfg_reply_error_string("link not found");
2599 } 2612 }
2600
2601 tipc_node_lock(node);
2602 link_reset_statistics(l_ptr); 2613 link_reset_statistics(l_ptr);
2603 tipc_node_unlock(node); 2614 tipc_node_unlock(node);
2604 read_unlock_bh(&tipc_net_lock); 2615 read_unlock_bh(&tipc_net_lock);
@@ -2628,18 +2639,27 @@ static int tipc_link_stats(const char *name, char *buf, const u32 buf_size)
2628 struct tipc_node *node; 2639 struct tipc_node *node;
2629 char *status; 2640 char *status;
2630 u32 profile_total = 0; 2641 u32 profile_total = 0;
2642 unsigned int bearer_id;
2631 int ret; 2643 int ret;
2632 2644
2633 if (!strcmp(name, tipc_bclink_name)) 2645 if (!strcmp(name, tipc_bclink_name))
2634 return tipc_bclink_stats(buf, buf_size); 2646 return tipc_bclink_stats(buf, buf_size);
2635 2647
2636 read_lock_bh(&tipc_net_lock); 2648 read_lock_bh(&tipc_net_lock);
2637 l = link_find_link(name, &node); 2649 node = tipc_link_find_owner(name, &bearer_id);
2638 if (!l) { 2650 if (!node) {
2639 read_unlock_bh(&tipc_net_lock); 2651 read_unlock_bh(&tipc_net_lock);
2640 return 0; 2652 return 0;
2641 } 2653 }
2642 tipc_node_lock(node); 2654 tipc_node_lock(node);
2655
2656 l = node->links[bearer_id];
2657 if (!l) {
2658 tipc_node_unlock(node);
2659 read_unlock_bh(&tipc_net_lock);
2660 return 0;
2661 }
2662
2643 s = &l->stats; 2663 s = &l->stats;
2644 2664
2645 if (tipc_link_is_active(l)) 2665 if (tipc_link_is_active(l))