aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
authorJon Paul Maloy <jon.maloy@ericsson.com>2015-02-03 08:59:17 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-04 19:09:31 -0500
commit2d72d49553d8de113d4eb1f69b2291f449a4c6bc (patch)
treec4b865c7d4a4e7b81438bba58042741865b403ae /net/tipc
parent940288b6a560710d4c63bc84d9570779dd7dec2b (diff)
tipc: add reference count to struct tipc_link
When a bearer is disabled, all pertaining links will be reset and deleted. However, if there is a second active link towards a killed link's destination, the delete has to be postponed until the failover is finished. During this interval, we currently put the link in zombie mode, i.e., we take it out of traffic, delete its timer, but leave it attached to the owner node structure until all missing packets have been received. When this is done, we detach the link from its node and delete it, assuming that the synchronous timer deletion that was initiated earlier in a different thread has finished. This is unsafe, as the failover may finish before del_timer_sync() has returned in the other thread. We fix this by adding an atomic reference counter of type kref in struct tipc_link. The counter keeps track of the references kept to the link by the owner node and the timer. We then do a conditional delete, based on the reference counter, both after the failover has been finished and when the timer expires, if applicable. Whoever comes last, will actually delete the link. This approach also implies that we can make the deletion of the timer asynchronous. Reviewed-by: Erik Hugne <erik.hugne@ericsson.com> Reviewed-by: Ying Xue <ying.xue@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/link.c79
-rw-r--r--net/tipc/link.h2
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
130static void tipc_link_release(struct kref *kref)
131{
132 kfree(container_of(kref, struct tipc_link, ref));
133}
134
135static void tipc_link_get(struct tipc_link *l_ptr)
136{
137 kref_get(&l_ptr->ref);
138}
139
140static void tipc_link_put(struct tipc_link *l_ptr)
141{
142 kref_put(&l_ptr->ref, tipc_link_release);
143}
144
130static void link_init_max_pkt(struct tipc_link *l_ptr) 145static 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
227static void link_set_timer(struct tipc_link *link, unsigned long time) 243static 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 */
337void 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
318void tipc_link_delete_list(struct net *net, unsigned int bearer_id, 344void 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 }
1839exit: 1858exit:
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;