aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
authorYing Xue <ying.xue@windriver.com>2014-02-13 17:29:09 -0500
committerDavid S. Miller <davem@davemloft.net>2014-02-13 17:57:05 -0500
commitc61dd61dec0b79fa22ded8b5caf2e817dc506c24 (patch)
treec81280b1339cb4822d9480ec4617dae2d94c3408 /net/tipc
parent135daee6d3959a6d7c4f59b448ed6f854d88ce27 (diff)
tipc: remove 'links' list from tipc_bearer struct
In our ongoing effort to simplify the TIPC locking structure, we see a need to remove the linked list for tipc_links in the bearer. This can be explained as follows. Currently, we have three different ways to access a link, via three different lists/tables: 1: Via a node hash table: Used by the time-critical outgoing/incoming data paths. (e.g. link_send_sections_fast() and tipc_recv_msg() ): grab net_lock(read) find node from node hash table grab node_lock select link grab bearer_lock send_msg() release bearer_lock release node lock release net_lock 2: Via a global linked list for nodes: Used by configuration commands (link_cmd_set_value()) grab net_lock(read) find node and link from global node list (using link name) grab node_lock update link release node lock release net_lock (Same locking order as above. No problem.) 3: Via the bearer's linked link list: Used by notifications from interface (e.g. tipc_disable_bearer() ) grab net_lock(write) grab bearer_lock get link ptr from bearer's link list get node from link grab node_lock delete link release node lock release bearer_lock release net_lock (Different order from above, but works because we grab the outer net_lock in write mode first, excluding all other access.) The first major goal in our simplification effort is to get rid of the "big" net_lock, replacing it with rcu-locks when accessing the node list and node hash array. This will come in a later patch series. But to get there we first need to rewrite access methods ##2 and 3, since removal of net_lock would introduce three major problems: 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, "tipc: add node lock protection to link found by link_find_link()". b) When the outer protection from net_lock is gone, taking bearer_lock and node_lock in opposite order of method 1) and 2) will become an obvious deadlock hazard. This is fixed in the commit ("tipc: remove bearer_lock from tipc_bearer struct") later in this series. c) Similar to what is described in problem a), access method #3 starts with using a link pointer that is unprotected by node_lock, in order to via that pointer find the correct node struct and lock it. Before we remove net_lock, this access order must be altered. This is what we do with this commit. We can avoid introducing problem problem c) by even here using the global node list to find the node, before accessing its links. When we loop though the node list we use the own bearer identity as search criteria, thus easily finding the links that are associated to the resetting/disabling bearer. It should be noted that although this method is somewhat slower than the current list traversal, it is in no way time critical. This is only about resetting or deleting links, something that must be considered relatively infrequent events. As a bonus, we can get rid of the mutual pointers between links and bearers. After this commit, pointer dependency go in one direction only: from the link to the bearer. This commit pre-empts introduction of problem c) as described above. Signed-off-by: Ying Xue <ying.xue@windriver.com> Reviewed-by: Paul Gortmaker <paul.gortmaker@windriver.com> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc')
-rw-r--r--net/tipc/bearer.c5
-rw-r--r--net/tipc/bearer.h2
-rw-r--r--net/tipc/core.c2
-rw-r--r--net/tipc/link.c67
-rw-r--r--net/tipc/link.h8
5 files changed, 30 insertions, 54 deletions
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index a5be053cac57..4931eea65797 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -327,7 +327,6 @@ restart:
327 b_ptr->net_plane = bearer_id + 'A'; 327 b_ptr->net_plane = bearer_id + 'A';
328 b_ptr->active = 1; 328 b_ptr->active = 1;
329 b_ptr->priority = priority; 329 b_ptr->priority = priority;
330 INIT_LIST_HEAD(&b_ptr->links);
331 spin_lock_init(&b_ptr->lock); 330 spin_lock_init(&b_ptr->lock);
332 331
333 res = tipc_disc_create(b_ptr, &b_ptr->bcast_addr, disc_domain); 332 res = tipc_disc_create(b_ptr, &b_ptr->bcast_addr, disc_domain);
@@ -353,7 +352,7 @@ static int tipc_reset_bearer(struct tipc_bearer *b_ptr)
353 read_lock_bh(&tipc_net_lock); 352 read_lock_bh(&tipc_net_lock);
354 pr_info("Resetting bearer <%s>\n", b_ptr->name); 353 pr_info("Resetting bearer <%s>\n", b_ptr->name);
355 spin_lock_bh(&b_ptr->lock); 354 spin_lock_bh(&b_ptr->lock);
356 tipc_link_reset_list(b_ptr); 355 tipc_link_reset_list(b_ptr->identity);
357 spin_unlock_bh(&b_ptr->lock); 356 spin_unlock_bh(&b_ptr->lock);
358 read_unlock_bh(&tipc_net_lock); 357 read_unlock_bh(&tipc_net_lock);
359 return 0; 358 return 0;
@@ -371,7 +370,7 @@ static void bearer_disable(struct tipc_bearer *b_ptr)
371 pr_info("Disabling bearer <%s>\n", b_ptr->name); 370 pr_info("Disabling bearer <%s>\n", b_ptr->name);
372 spin_lock_bh(&b_ptr->lock); 371 spin_lock_bh(&b_ptr->lock);
373 b_ptr->media->disable_media(b_ptr); 372 b_ptr->media->disable_media(b_ptr);
374 tipc_link_delete_list(b_ptr); 373 tipc_link_delete_list(b_ptr->identity);
375 temp_req = b_ptr->link_req; 374 temp_req = b_ptr->link_req;
376 b_ptr->link_req = NULL; 375 b_ptr->link_req = NULL;
377 spin_unlock_bh(&b_ptr->lock); 376 spin_unlock_bh(&b_ptr->lock);
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index 4f5db9ad5bf6..647cb1d2324a 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -120,7 +120,6 @@ struct tipc_media {
120 * @tolerance: default link tolerance for bearer 120 * @tolerance: default link tolerance for bearer
121 * @identity: array index of this bearer within TIPC bearer array 121 * @identity: array index of this bearer within TIPC bearer array
122 * @link_req: ptr to (optional) structure making periodic link setup requests 122 * @link_req: ptr to (optional) structure making periodic link setup requests
123 * @links: list of non-congested links associated with bearer
124 * @active: non-zero if bearer structure is represents a bearer 123 * @active: non-zero if bearer structure is represents a bearer
125 * @net_plane: network plane ('A' through 'H') currently associated with bearer 124 * @net_plane: network plane ('A' through 'H') currently associated with bearer
126 * @nodes: indicates which nodes in cluster can be reached through bearer 125 * @nodes: indicates which nodes in cluster can be reached through bearer
@@ -142,7 +141,6 @@ struct tipc_bearer {
142 u32 tolerance; 141 u32 tolerance;
143 u32 identity; 142 u32 identity;
144 struct tipc_link_req *link_req; 143 struct tipc_link_req *link_req;
145 struct list_head links;
146 int active; 144 int active;
147 char net_plane; 145 char net_plane;
148 struct tipc_node_map nodes; 146 struct tipc_node_map nodes;
diff --git a/net/tipc/core.c b/net/tipc/core.c
index f9e88d8b04ca..3f76b98d2fed 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * net/tipc/core.c: TIPC module code 2 * net/tipc/core.c: TIPC module code
3 * 3 *
4 * Copyright (c) 2003-2006, Ericsson AB 4 * Copyright (c) 2003-2006, 2013, Ericsson AB
5 * Copyright (c) 2005-2006, 2010-2013, Wind River Systems 5 * Copyright (c) 2005-2006, 2010-2013, Wind River Systems
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 2070d032c923..e7e44ab008ec 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -147,11 +147,6 @@ int tipc_link_is_active(struct tipc_link *l_ptr)
147/** 147/**
148 * link_timeout - handle expiration of link timer 148 * link_timeout - handle expiration of link timer
149 * @l_ptr: pointer to link 149 * @l_ptr: pointer to link
150 *
151 * This routine must not grab "tipc_net_lock" to avoid a potential deadlock conflict
152 * with tipc_link_delete(). (There is no risk that the node will be deleted by
153 * another thread because tipc_link_delete() always cancels the link timer before
154 * tipc_node_delete() is called.)
155 */ 150 */
156static void link_timeout(struct tipc_link *l_ptr) 151static void link_timeout(struct tipc_link *l_ptr)
157{ 152{
@@ -213,8 +208,8 @@ static void link_set_timer(struct tipc_link *l_ptr, u32 time)
213 * Returns pointer to link. 208 * Returns pointer to link.
214 */ 209 */
215struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, 210struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
216 struct tipc_bearer *b_ptr, 211 struct tipc_bearer *b_ptr,
217 const struct tipc_media_addr *media_addr) 212 const struct tipc_media_addr *media_addr)
218{ 213{
219 struct tipc_link *l_ptr; 214 struct tipc_link *l_ptr;
220 struct tipc_msg *msg; 215 struct tipc_msg *msg;
@@ -279,47 +274,32 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
279 274
280 k_init_timer(&l_ptr->timer, (Handler)link_timeout, 275 k_init_timer(&l_ptr->timer, (Handler)link_timeout,
281 (unsigned long)l_ptr); 276 (unsigned long)l_ptr);
282 list_add_tail(&l_ptr->link_list, &b_ptr->links);
283 277
284 link_state_event(l_ptr, STARTING_EVT); 278 link_state_event(l_ptr, STARTING_EVT);
285 279
286 return l_ptr; 280 return l_ptr;
287} 281}
288 282
289/**
290 * tipc_link_delete - delete a link
291 * @l_ptr: pointer to link
292 *
293 * Note: 'tipc_net_lock' is write_locked, bearer is locked.
294 * This routine must not grab the node lock until after link timer cancellation
295 * to avoid a potential deadlock situation.
296 */
297void tipc_link_delete(struct tipc_link *l_ptr)
298{
299 if (!l_ptr) {
300 pr_err("Attempt to delete non-existent link\n");
301 return;
302 }
303
304 k_cancel_timer(&l_ptr->timer);
305 283
306 tipc_node_lock(l_ptr->owner); 284void tipc_link_delete_list(unsigned int bearer_id)
307 tipc_link_reset(l_ptr);
308 tipc_node_detach_link(l_ptr->owner, l_ptr);
309 tipc_link_purge_queues(l_ptr);
310 list_del_init(&l_ptr->link_list);
311 tipc_node_unlock(l_ptr->owner);
312 k_term_timer(&l_ptr->timer);
313 kfree(l_ptr);
314}
315
316void tipc_link_delete_list(struct tipc_bearer *b_ptr)
317{ 285{
318 struct tipc_link *l_ptr; 286 struct tipc_link *l_ptr;
319 struct tipc_link *temp_l_ptr; 287 struct tipc_node *n_ptr;
320 288
321 list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { 289 list_for_each_entry(n_ptr, &tipc_node_list, list) {
322 tipc_link_delete(l_ptr); 290 spin_lock_bh(&n_ptr->lock);
291 l_ptr = n_ptr->links[bearer_id];
292 if (l_ptr) {
293 tipc_link_reset(l_ptr);
294 tipc_node_detach_link(n_ptr, l_ptr);
295 spin_unlock_bh(&n_ptr->lock);
296
297 /* Nobody else can access this link now: */
298 del_timer_sync(&l_ptr->timer);
299 kfree(l_ptr);
300 continue;
301 }
302 spin_unlock_bh(&n_ptr->lock);
323 } 303 }
324} 304}
325 305
@@ -470,15 +450,16 @@ void tipc_link_reset(struct tipc_link *l_ptr)
470 link_reset_statistics(l_ptr); 450 link_reset_statistics(l_ptr);
471} 451}
472 452
473void tipc_link_reset_list(struct tipc_bearer *b_ptr) 453void tipc_link_reset_list(unsigned int bearer_id)
474{ 454{
475 struct tipc_link *l_ptr; 455 struct tipc_link *l_ptr;
456 struct tipc_node *n_ptr;
476 457
477 list_for_each_entry(l_ptr, &b_ptr->links, link_list) { 458 list_for_each_entry(n_ptr, &tipc_node_list, list) {
478 struct tipc_node *n_ptr = l_ptr->owner;
479
480 spin_lock_bh(&n_ptr->lock); 459 spin_lock_bh(&n_ptr->lock);
481 tipc_link_reset(l_ptr); 460 l_ptr = n_ptr->links[bearer_id];
461 if (l_ptr)
462 tipc_link_reset(l_ptr);
482 spin_unlock_bh(&n_ptr->lock); 463 spin_unlock_bh(&n_ptr->lock);
483 } 464 }
484} 465}
diff --git a/net/tipc/link.h b/net/tipc/link.h
index a900e74b4f3a..3340fc1fc299 100644
--- a/net/tipc/link.h
+++ b/net/tipc/link.h
@@ -59,6 +59,7 @@
59/* Link endpoint execution states 59/* Link endpoint execution states
60 */ 60 */
61#define LINK_STARTED 0x0001 61#define LINK_STARTED 0x0001
62#define LINK_STOPPED 0x0002
62 63
63/* Starting value for maximum packet size negotiation on unicast links 64/* Starting value for maximum packet size negotiation on unicast links
64 * (unless bearer MTU is less) 65 * (unless bearer MTU is less)
@@ -102,7 +103,6 @@ struct tipc_stats {
102 * @media_addr: media address to use when sending messages over link 103 * @media_addr: media address to use when sending messages over link
103 * @timer: link timer 104 * @timer: link timer
104 * @owner: pointer to peer node 105 * @owner: pointer to peer node
105 * @link_list: adjacent links in bearer's list of links
106 * @flags: execution state flags for link endpoint instance 106 * @flags: execution state flags for link endpoint instance
107 * @checkpoint: reference point for triggering link continuity checking 107 * @checkpoint: reference point for triggering link continuity checking
108 * @peer_session: link session # being used by peer end of link 108 * @peer_session: link session # being used by peer end of link
@@ -149,7 +149,6 @@ struct tipc_link {
149 struct tipc_media_addr media_addr; 149 struct tipc_media_addr media_addr;
150 struct timer_list timer; 150 struct timer_list timer;
151 struct tipc_node *owner; 151 struct tipc_node *owner;
152 struct list_head link_list;
153 152
154 /* Management and link supervision data */ 153 /* Management and link supervision data */
155 unsigned int flags; 154 unsigned int flags;
@@ -215,11 +214,10 @@ struct tipc_port;
215struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, 214struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
216 struct tipc_bearer *b_ptr, 215 struct tipc_bearer *b_ptr,
217 const struct tipc_media_addr *media_addr); 216 const struct tipc_media_addr *media_addr);
218void tipc_link_delete(struct tipc_link *l_ptr); 217void tipc_link_delete_list(unsigned int bearer_id);
219void tipc_link_failover_send_queue(struct tipc_link *l_ptr); 218void tipc_link_failover_send_queue(struct tipc_link *l_ptr);
220void tipc_link_dup_send_queue(struct tipc_link *l_ptr, 219void tipc_link_dup_send_queue(struct tipc_link *l_ptr,
221 struct tipc_link *dest); 220 struct tipc_link *dest);
222void tipc_link_delete_list(struct tipc_bearer *b_ptr);
223void tipc_link_reset_fragments(struct tipc_link *l_ptr); 221void tipc_link_reset_fragments(struct tipc_link *l_ptr);
224int tipc_link_is_up(struct tipc_link *l_ptr); 222int tipc_link_is_up(struct tipc_link *l_ptr);
225int tipc_link_is_active(struct tipc_link *l_ptr); 223int tipc_link_is_active(struct tipc_link *l_ptr);
@@ -232,7 +230,7 @@ struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area,
232struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, 230struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area,
233 int req_tlv_space); 231 int req_tlv_space);
234void tipc_link_reset(struct tipc_link *l_ptr); 232void tipc_link_reset(struct tipc_link *l_ptr);
235void tipc_link_reset_list(struct tipc_bearer *b_ptr); 233void tipc_link_reset_list(unsigned int bearer_id);
236int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector); 234int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector);
237void tipc_link_send_names(struct list_head *message_list, u32 dest); 235void tipc_link_send_names(struct list_head *message_list, u32 dest);
238int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf); 236int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf);