diff options
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/link.c | 79 | ||||
-rw-r--r-- | net/tipc/link.h | 2 |
2 files changed, 50 insertions, 31 deletions
diff --git a/net/tipc/link.c b/net/tipc/link.c index 2846ad802e43..46aa59955299 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
@@ -127,6 +127,21 @@ static unsigned int align(unsigned int i) | |||
127 | return (i + 3) & ~3u; | 127 | return (i + 3) & ~3u; |
128 | } | 128 | } |
129 | 129 | ||
130 | static void tipc_link_release(struct kref *kref) | ||
131 | { | ||
132 | kfree(container_of(kref, struct tipc_link, ref)); | ||
133 | } | ||
134 | |||
135 | static void tipc_link_get(struct tipc_link *l_ptr) | ||
136 | { | ||
137 | kref_get(&l_ptr->ref); | ||
138 | } | ||
139 | |||
140 | static void tipc_link_put(struct tipc_link *l_ptr) | ||
141 | { | ||
142 | kref_put(&l_ptr->ref, tipc_link_release); | ||
143 | } | ||
144 | |||
130 | static void link_init_max_pkt(struct tipc_link *l_ptr) | 145 | static void link_init_max_pkt(struct tipc_link *l_ptr) |
131 | { | 146 | { |
132 | struct tipc_node *node = l_ptr->owner; | 147 | struct tipc_node *node = l_ptr->owner; |
@@ -222,11 +237,13 @@ static void link_timeout(unsigned long data) | |||
222 | tipc_link_push_packets(l_ptr); | 237 | tipc_link_push_packets(l_ptr); |
223 | 238 | ||
224 | tipc_node_unlock(l_ptr->owner); | 239 | tipc_node_unlock(l_ptr->owner); |
240 | tipc_link_put(l_ptr); | ||
225 | } | 241 | } |
226 | 242 | ||
227 | static void link_set_timer(struct tipc_link *link, unsigned long time) | 243 | static void link_set_timer(struct tipc_link *link, unsigned long time) |
228 | { | 244 | { |
229 | mod_timer(&link->timer, jiffies + time); | 245 | if (!mod_timer(&link->timer, jiffies + time)) |
246 | tipc_link_get(link); | ||
230 | } | 247 | } |
231 | 248 | ||
232 | /** | 249 | /** |
@@ -267,7 +284,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, | |||
267 | pr_warn("Link creation failed, no memory\n"); | 284 | pr_warn("Link creation failed, no memory\n"); |
268 | return NULL; | 285 | return NULL; |
269 | } | 286 | } |
270 | 287 | kref_init(&l_ptr->ref); | |
271 | l_ptr->addr = peer; | 288 | l_ptr->addr = peer; |
272 | if_name = strchr(b_ptr->name, ':') + 1; | 289 | if_name = strchr(b_ptr->name, ':') + 1; |
273 | sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:unknown", | 290 | sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:unknown", |
@@ -305,46 +322,48 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, | |||
305 | skb_queue_head_init(&l_ptr->waiting_sks); | 322 | skb_queue_head_init(&l_ptr->waiting_sks); |
306 | 323 | ||
307 | link_reset_statistics(l_ptr); | 324 | link_reset_statistics(l_ptr); |
308 | |||
309 | tipc_node_attach_link(n_ptr, l_ptr); | 325 | tipc_node_attach_link(n_ptr, l_ptr); |
310 | |||
311 | setup_timer(&l_ptr->timer, link_timeout, (unsigned long)l_ptr); | 326 | setup_timer(&l_ptr->timer, link_timeout, (unsigned long)l_ptr); |
312 | |||
313 | link_state_event(l_ptr, STARTING_EVT); | 327 | link_state_event(l_ptr, STARTING_EVT); |
314 | 328 | ||
315 | return l_ptr; | 329 | return l_ptr; |
316 | } | 330 | } |
317 | 331 | ||
332 | /** | ||
333 | * link_delete - Conditional deletion of link. | ||
334 | * If timer still running, real delete is done when it expires | ||
335 | * @link: link to be deleted | ||
336 | */ | ||
337 | void tipc_link_delete(struct tipc_link *link) | ||
338 | { | ||
339 | tipc_link_reset_fragments(link); | ||
340 | tipc_node_detach_link(link->owner, link); | ||
341 | tipc_link_put(link); | ||
342 | } | ||
343 | |||
318 | void tipc_link_delete_list(struct net *net, unsigned int bearer_id, | 344 | void tipc_link_delete_list(struct net *net, unsigned int bearer_id, |
319 | bool shutting_down) | 345 | bool shutting_down) |
320 | { | 346 | { |
321 | struct tipc_net *tn = net_generic(net, tipc_net_id); | 347 | struct tipc_net *tn = net_generic(net, tipc_net_id); |
322 | struct tipc_link *l_ptr; | 348 | struct tipc_link *link; |
323 | struct tipc_node *n_ptr; | 349 | struct tipc_node *node; |
324 | 350 | ||
325 | rcu_read_lock(); | 351 | rcu_read_lock(); |
326 | list_for_each_entry_rcu(n_ptr, &tn->node_list, list) { | 352 | list_for_each_entry_rcu(node, &tn->node_list, list) { |
327 | tipc_node_lock(n_ptr); | 353 | tipc_node_lock(node); |
328 | l_ptr = n_ptr->links[bearer_id]; | 354 | link = node->links[bearer_id]; |
329 | if (l_ptr) { | 355 | if (!link) { |
330 | tipc_link_reset(l_ptr); | 356 | tipc_node_unlock(node); |
331 | if (shutting_down || !tipc_node_is_up(n_ptr)) { | ||
332 | tipc_node_detach_link(l_ptr->owner, l_ptr); | ||
333 | tipc_link_reset_fragments(l_ptr); | ||
334 | tipc_node_unlock(n_ptr); | ||
335 | |||
336 | /* Nobody else can access this link now: */ | ||
337 | del_timer_sync(&l_ptr->timer); | ||
338 | kfree(l_ptr); | ||
339 | } else { | ||
340 | /* Detach/delete when failover is finished: */ | ||
341 | l_ptr->flags |= LINK_STOPPED; | ||
342 | tipc_node_unlock(n_ptr); | ||
343 | del_timer_sync(&l_ptr->timer); | ||
344 | } | ||
345 | continue; | 357 | continue; |
346 | } | 358 | } |
347 | tipc_node_unlock(n_ptr); | 359 | tipc_link_reset(link); |
360 | if (del_timer(&link->timer)) | ||
361 | tipc_link_put(link); | ||
362 | link->flags |= LINK_STOPPED; | ||
363 | /* Delete link now, or when failover is finished: */ | ||
364 | if (shutting_down || !tipc_node_is_up(node)) | ||
365 | tipc_link_delete(link); | ||
366 | tipc_node_unlock(node); | ||
348 | } | 367 | } |
349 | rcu_read_unlock(); | 368 | rcu_read_unlock(); |
350 | } | 369 | } |
@@ -1837,10 +1856,8 @@ static struct sk_buff *tipc_link_failover_rcv(struct tipc_link *l_ptr, | |||
1837 | } | 1856 | } |
1838 | } | 1857 | } |
1839 | exit: | 1858 | exit: |
1840 | if ((l_ptr->exp_msg_count == 0) && (l_ptr->flags & LINK_STOPPED)) { | 1859 | if ((!l_ptr->exp_msg_count) && (l_ptr->flags & LINK_STOPPED)) |
1841 | tipc_node_detach_link(l_ptr->owner, l_ptr); | 1860 | tipc_link_delete(l_ptr); |
1842 | kfree(l_ptr); | ||
1843 | } | ||
1844 | return buf; | 1861 | return buf; |
1845 | } | 1862 | } |
1846 | 1863 | ||
diff --git a/net/tipc/link.h b/net/tipc/link.h index 9df7fa4d3bdd..f06b779c9f75 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h | |||
@@ -103,6 +103,7 @@ struct tipc_stats { | |||
103 | * @media_addr: media address to use when sending messages over link | 103 | * @media_addr: media address to use when sending messages over link |
104 | * @timer: link timer | 104 | * @timer: link timer |
105 | * @owner: pointer to peer node | 105 | * @owner: pointer to peer node |
106 | * @refcnt: reference counter for permanent references (owner node & timer) | ||
106 | * @flags: execution state flags for link endpoint instance | 107 | * @flags: execution state flags for link endpoint instance |
107 | * @checkpoint: reference point for triggering link continuity checking | 108 | * @checkpoint: reference point for triggering link continuity checking |
108 | * @peer_session: link session # being used by peer end of link | 109 | * @peer_session: link session # being used by peer end of link |
@@ -142,6 +143,7 @@ struct tipc_link { | |||
142 | struct tipc_media_addr media_addr; | 143 | struct tipc_media_addr media_addr; |
143 | struct timer_list timer; | 144 | struct timer_list timer; |
144 | struct tipc_node *owner; | 145 | struct tipc_node *owner; |
146 | struct kref ref; | ||
145 | 147 | ||
146 | /* Management and link supervision data */ | 148 | /* Management and link supervision data */ |
147 | unsigned int flags; | 149 | unsigned int flags; |