Skip to content

Commit c61dd61

Browse files
ying-xuedavem330
authored andcommitted
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 <[email protected]> Reviewed-by: Paul Gortmaker <[email protected]> Signed-off-by: Jon Maloy <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 135daee commit c61dd61

File tree

5 files changed

+30
-54
lines changed

5 files changed

+30
-54
lines changed

net/tipc/bearer.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,6 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
327327
b_ptr->net_plane = bearer_id + 'A';
328328
b_ptr->active = 1;
329329
b_ptr->priority = priority;
330-
INIT_LIST_HEAD(&b_ptr->links);
331330
spin_lock_init(&b_ptr->lock);
332331

333332
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)
353352
read_lock_bh(&tipc_net_lock);
354353
pr_info("Resetting bearer <%s>\n", b_ptr->name);
355354
spin_lock_bh(&b_ptr->lock);
356-
tipc_link_reset_list(b_ptr);
355+
tipc_link_reset_list(b_ptr->identity);
357356
spin_unlock_bh(&b_ptr->lock);
358357
read_unlock_bh(&tipc_net_lock);
359358
return 0;
@@ -371,7 +370,7 @@ static void bearer_disable(struct tipc_bearer *b_ptr)
371370
pr_info("Disabling bearer <%s>\n", b_ptr->name);
372371
spin_lock_bh(&b_ptr->lock);
373372
b_ptr->media->disable_media(b_ptr);
374-
tipc_link_delete_list(b_ptr);
373+
tipc_link_delete_list(b_ptr->identity);
375374
temp_req = b_ptr->link_req;
376375
b_ptr->link_req = NULL;
377376
spin_unlock_bh(&b_ptr->lock);

net/tipc/bearer.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ struct tipc_media {
120120
* @tolerance: default link tolerance for bearer
121121
* @identity: array index of this bearer within TIPC bearer array
122122
* @link_req: ptr to (optional) structure making periodic link setup requests
123-
* @links: list of non-congested links associated with bearer
124123
* @active: non-zero if bearer structure is represents a bearer
125124
* @net_plane: network plane ('A' through 'H') currently associated with bearer
126125
* @nodes: indicates which nodes in cluster can be reached through bearer
@@ -142,7 +141,6 @@ struct tipc_bearer {
142141
u32 tolerance;
143142
u32 identity;
144143
struct tipc_link_req *link_req;
145-
struct list_head links;
146144
int active;
147145
char net_plane;
148146
struct tipc_node_map nodes;

net/tipc/core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* net/tipc/core.c: TIPC module code
33
*
4-
* Copyright (c) 2003-2006, Ericsson AB
4+
* Copyright (c) 2003-2006, 2013, Ericsson AB
55
* Copyright (c) 2005-2006, 2010-2013, Wind River Systems
66
* All rights reserved.
77
*

net/tipc/link.c

Lines changed: 24 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,6 @@ int tipc_link_is_active(struct tipc_link *l_ptr)
147147
/**
148148
* link_timeout - handle expiration of link timer
149149
* @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.)
155150
*/
156151
static void link_timeout(struct tipc_link *l_ptr)
157152
{
@@ -213,8 +208,8 @@ static void link_set_timer(struct tipc_link *l_ptr, u32 time)
213208
* Returns pointer to link.
214209
*/
215210
struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
216-
struct tipc_bearer *b_ptr,
217-
const struct tipc_media_addr *media_addr)
211+
struct tipc_bearer *b_ptr,
212+
const struct tipc_media_addr *media_addr)
218213
{
219214
struct tipc_link *l_ptr;
220215
struct tipc_msg *msg;
@@ -279,47 +274,32 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
279274

280275
k_init_timer(&l_ptr->timer, (Handler)link_timeout,
281276
(unsigned long)l_ptr);
282-
list_add_tail(&l_ptr->link_list, &b_ptr->links);
283277

284278
link_state_event(l_ptr, STARTING_EVT);
285279

286280
return l_ptr;
287281
}
288282

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-
*/
297-
void 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);
305283

306-
tipc_node_lock(l_ptr->owner);
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-
316-
void tipc_link_delete_list(struct tipc_bearer *b_ptr)
284+
void tipc_link_delete_list(unsigned int bearer_id)
317285
{
318286
struct tipc_link *l_ptr;
319-
struct tipc_link *temp_l_ptr;
287+
struct tipc_node *n_ptr;
320288

321-
list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
322-
tipc_link_delete(l_ptr);
289+
list_for_each_entry(n_ptr, &tipc_node_list, list) {
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);
323303
}
324304
}
325305

@@ -470,15 +450,16 @@ void tipc_link_reset(struct tipc_link *l_ptr)
470450
link_reset_statistics(l_ptr);
471451
}
472452

473-
void tipc_link_reset_list(struct tipc_bearer *b_ptr)
453+
void tipc_link_reset_list(unsigned int bearer_id)
474454
{
475455
struct tipc_link *l_ptr;
456+
struct tipc_node *n_ptr;
476457

477-
list_for_each_entry(l_ptr, &b_ptr->links, link_list) {
478-
struct tipc_node *n_ptr = l_ptr->owner;
479-
458+
list_for_each_entry(n_ptr, &tipc_node_list, list) {
480459
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);
482463
spin_unlock_bh(&n_ptr->lock);
483464
}
484465
}

net/tipc/link.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
/* Link endpoint execution states
6060
*/
6161
#define LINK_STARTED 0x0001
62+
#define LINK_STOPPED 0x0002
6263

6364
/* Starting value for maximum packet size negotiation on unicast links
6465
* (unless bearer MTU is less)
@@ -102,7 +103,6 @@ struct tipc_stats {
102103
* @media_addr: media address to use when sending messages over link
103104
* @timer: link timer
104105
* @owner: pointer to peer node
105-
* @link_list: adjacent links in bearer's list of links
106106
* @flags: execution state flags for link endpoint instance
107107
* @checkpoint: reference point for triggering link continuity checking
108108
* @peer_session: link session # being used by peer end of link
@@ -149,7 +149,6 @@ struct tipc_link {
149149
struct tipc_media_addr media_addr;
150150
struct timer_list timer;
151151
struct tipc_node *owner;
152-
struct list_head link_list;
153152

154153
/* Management and link supervision data */
155154
unsigned int flags;
@@ -215,11 +214,10 @@ struct tipc_port;
215214
struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
216215
struct tipc_bearer *b_ptr,
217216
const struct tipc_media_addr *media_addr);
218-
void tipc_link_delete(struct tipc_link *l_ptr);
217+
void tipc_link_delete_list(unsigned int bearer_id);
219218
void tipc_link_failover_send_queue(struct tipc_link *l_ptr);
220219
void tipc_link_dup_send_queue(struct tipc_link *l_ptr,
221220
struct tipc_link *dest);
222-
void tipc_link_delete_list(struct tipc_bearer *b_ptr);
223221
void tipc_link_reset_fragments(struct tipc_link *l_ptr);
224222
int tipc_link_is_up(struct tipc_link *l_ptr);
225223
int 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,
232230
struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area,
233231
int req_tlv_space);
234232
void tipc_link_reset(struct tipc_link *l_ptr);
235-
void tipc_link_reset_list(struct tipc_bearer *b_ptr);
233+
void tipc_link_reset_list(unsigned int bearer_id);
236234
int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector);
237235
void tipc_link_send_names(struct list_head *message_list, u32 dest);
238236
int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf);

0 commit comments

Comments
 (0)