aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
authorErik Hugne <erik.hugne@ericsson.com>2013-12-06 10:08:00 -0500
committerDavid S. Miller <davem@davemloft.net>2013-12-09 20:30:29 -0500
commit512137eeff00f73a8a62e481a6575f1556cf962c (patch)
treec588e741a1587dc34835871110949ef92b5faab7 /net/tipc
parentb73e9e3cf06ef8180c75a6bd28cdd1b833d22a3a (diff)
tipc: remove interface state mirroring in bearer
struct 'tipc_bearer' is a generic representation of the underlying media type, and exists in a one-to-one relationship to each interface TIPC is using. The struct contains a 'blocked' flag that mirrors the operational and execution state of the represented interface, and is updated through notification calls from the latter. The users of tipc_bearer are checking this flag before each attempt to send a packet via the interface. This state mirroring serves no purpose in the current code base. TIPC links will not discover a media failure any faster through this mechanism, and in reality the flag only adds overhead at packet sending and reception. Furthermore, the fact that the flag needs to be protected by a spinlock aggregated into tipc_bearer has turned out to cause a serious and completely unnecessary deadlock problem. CPU0 CPU1 ---- ---- Time 0: bearer_disable() link_timeout() Time 1: spin_lock_bh(&b_ptr->lock) tipc_link_push_queue() Time 2: tipc_link_delete() tipc_bearer_blocked(b_ptr) Time 3: k_cancel_timer(&req->timer) spin_lock_bh(&b_ptr->lock) Time 4: del_timer_sync(&req->timer) I.e., del_timer_sync() on CPU0 never returns, because the timer handler on CPU1 is waiting for the bearer lock. We eliminate the 'blocked' flag from struct tipc_bearer, along with all tests on this flag. This not only resolves the deadlock, but also simplifies and speeds up the data path execution of TIPC. It also fits well into our ongoing effort to make the locking policy simpler and more manageable. An effect of this change is that we can get rid of functions such as tipc_bearer_blocked(), tipc_continue() and tipc_block_bearer(). We replace the latter with a new function, tipc_reset_bearer(), which resets all links associated to the bearer immediately after an interface goes down. A user might notice one slight change in link behaviour after this change. When an interface goes down, (e.g. through a NETDEV_DOWN event) all attached links will be reset immediately, instead of leaving it to each link to detect the failure through a timer-driven mechanism. We consider this an improvement, and see no obvious risks with the new behavior. Signed-off-by: Erik Hugne <erik.hugne@ericsson.com> Reviewed-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/bcast.c6
-rw-r--r--net/tipc/bearer.c33
-rw-r--r--net/tipc/bearer.h6
-rw-r--r--net/tipc/discover.c17
-rw-r--r--net/tipc/eth_media.c14
-rw-r--r--net/tipc/ib_media.c14
-rw-r--r--net/tipc/link.c55
7 files changed, 28 insertions, 117 deletions
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index 0d4402587fdf..4c2a80b3c01e 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -621,12 +621,6 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1,
621 if (!p) 621 if (!p)
622 break; /* No more bearers to try */ 622 break; /* No more bearers to try */
623 623
624 if (tipc_bearer_blocked(p)) {
625 if (!s || tipc_bearer_blocked(s))
626 continue; /* Can't use either bearer */
627 b = s;
628 }
629
630 tipc_nmap_diff(&bcbearer->remains, &b->nodes, 624 tipc_nmap_diff(&bcbearer->remains, &b->nodes,
631 &bcbearer->remains_new); 625 &bcbearer->remains_new);
632 if (bcbearer->remains_new.count == bcbearer->remains.count) 626 if (bcbearer->remains_new.count == bcbearer->remains.count)
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 3f9707a16d06..c2101c0bfd6d 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -275,31 +275,6 @@ void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest)
275 tipc_disc_remove_dest(b_ptr->link_req); 275 tipc_disc_remove_dest(b_ptr->link_req);
276} 276}
277 277
278/*
279 * Interrupt enabling new requests after bearer blocking:
280 * See bearer_send().
281 */
282void tipc_continue(struct tipc_bearer *b)
283{
284 spin_lock_bh(&b->lock);
285 b->blocked = 0;
286 spin_unlock_bh(&b->lock);
287}
288
289/*
290 * tipc_bearer_blocked - determines if bearer is currently blocked
291 */
292int tipc_bearer_blocked(struct tipc_bearer *b)
293{
294 int res;
295
296 spin_lock_bh(&b->lock);
297 res = b->blocked;
298 spin_unlock_bh(&b->lock);
299
300 return res;
301}
302
303/** 278/**
304 * tipc_enable_bearer - enable bearer with the given name 279 * tipc_enable_bearer - enable bearer with the given name
305 */ 280 */
@@ -420,17 +395,16 @@ exit:
420} 395}
421 396
422/** 397/**
423 * tipc_block_bearer - Block the bearer, and reset all its links 398 * tipc_reset_bearer - Reset all links established over this bearer
424 */ 399 */
425int tipc_block_bearer(struct tipc_bearer *b_ptr) 400int tipc_reset_bearer(struct tipc_bearer *b_ptr)
426{ 401{
427 struct tipc_link *l_ptr; 402 struct tipc_link *l_ptr;
428 struct tipc_link *temp_l_ptr; 403 struct tipc_link *temp_l_ptr;
429 404
430 read_lock_bh(&tipc_net_lock); 405 read_lock_bh(&tipc_net_lock);
431 pr_info("Blocking bearer <%s>\n", b_ptr->name); 406 pr_info("Resetting bearer <%s>\n", b_ptr->name);
432 spin_lock_bh(&b_ptr->lock); 407 spin_lock_bh(&b_ptr->lock);
433 b_ptr->blocked = 1;
434 list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { 408 list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
435 struct tipc_node *n_ptr = l_ptr->owner; 409 struct tipc_node *n_ptr = l_ptr->owner;
436 410
@@ -456,7 +430,6 @@ static void bearer_disable(struct tipc_bearer *b_ptr)
456 430
457 pr_info("Disabling bearer <%s>\n", b_ptr->name); 431 pr_info("Disabling bearer <%s>\n", b_ptr->name);
458 spin_lock_bh(&b_ptr->lock); 432 spin_lock_bh(&b_ptr->lock);
459 b_ptr->blocked = 1;
460 b_ptr->media->disable_media(b_ptr); 433 b_ptr->media->disable_media(b_ptr);
461 list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { 434 list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
462 tipc_link_delete(l_ptr); 435 tipc_link_delete(l_ptr);
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index e5e04be6fffa..cc780bbedbb9 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -108,7 +108,6 @@ struct tipc_media {
108 * struct tipc_bearer - TIPC bearer structure 108 * struct tipc_bearer - TIPC bearer structure
109 * @usr_handle: pointer to additional media-specific information about bearer 109 * @usr_handle: pointer to additional media-specific information about bearer
110 * @mtu: max packet size bearer can support 110 * @mtu: max packet size bearer can support
111 * @blocked: non-zero if bearer is blocked
112 * @lock: spinlock for controlling access to bearer 111 * @lock: spinlock for controlling access to bearer
113 * @addr: media-specific address associated with bearer 112 * @addr: media-specific address associated with bearer
114 * @name: bearer name (format = media:interface) 113 * @name: bearer name (format = media:interface)
@@ -130,7 +129,6 @@ struct tipc_media {
130struct tipc_bearer { 129struct tipc_bearer {
131 void *usr_handle; /* initalized by media */ 130 void *usr_handle; /* initalized by media */
132 u32 mtu; /* initalized by media */ 131 u32 mtu; /* initalized by media */
133 int blocked; /* initalized by media */
134 struct tipc_media_addr addr; /* initalized by media */ 132 struct tipc_media_addr addr; /* initalized by media */
135 char name[TIPC_MAX_BEARER_NAME]; 133 char name[TIPC_MAX_BEARER_NAME];
136 spinlock_t lock; 134 spinlock_t lock;
@@ -163,8 +161,7 @@ int tipc_register_media(struct tipc_media *m_ptr);
163 161
164void tipc_recv_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr); 162void tipc_recv_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr);
165 163
166int tipc_block_bearer(struct tipc_bearer *b_ptr); 164int tipc_reset_bearer(struct tipc_bearer *b_ptr);
167void tipc_continue(struct tipc_bearer *tb_ptr);
168 165
169int tipc_enable_bearer(const char *bearer_name, u32 disc_domain, u32 priority); 166int tipc_enable_bearer(const char *bearer_name, u32 disc_domain, u32 priority);
170int tipc_disable_bearer(const char *name); 167int tipc_disable_bearer(const char *name);
@@ -194,7 +191,6 @@ void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest);
194struct tipc_bearer *tipc_bearer_find(const char *name); 191struct tipc_bearer *tipc_bearer_find(const char *name);
195struct tipc_bearer *tipc_bearer_find_interface(const char *if_name); 192struct tipc_bearer *tipc_bearer_find_interface(const char *if_name);
196struct tipc_media *tipc_media_find(const char *name); 193struct tipc_media *tipc_media_find(const char *name);
197int tipc_bearer_blocked(struct tipc_bearer *b_ptr);
198void tipc_bearer_stop(void); 194void tipc_bearer_stop(void);
199 195
200/** 196/**
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index ecc758c6eacf..bc849f1efa16 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -239,7 +239,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr)
239 /* Accept discovery message & send response, if necessary */ 239 /* Accept discovery message & send response, if necessary */
240 link_fully_up = link_working_working(link); 240 link_fully_up = link_working_working(link);
241 241
242 if ((type == DSC_REQ_MSG) && !link_fully_up && !b_ptr->blocked) { 242 if ((type == DSC_REQ_MSG) && !link_fully_up) {
243 rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr); 243 rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr);
244 if (rbuf) { 244 if (rbuf) {
245 tipc_bearer_send(b_ptr, rbuf, &media_addr); 245 tipc_bearer_send(b_ptr, rbuf, &media_addr);
@@ -288,16 +288,6 @@ void tipc_disc_remove_dest(struct tipc_link_req *req)
288} 288}
289 289
290/** 290/**
291 * disc_send_msg - send link setup request message
292 * @req: ptr to link request structure
293 */
294static void disc_send_msg(struct tipc_link_req *req)
295{
296 if (!req->bearer->blocked)
297 tipc_bearer_send(req->bearer, req->buf, &req->dest);
298}
299
300/**
301 * disc_timeout - send a periodic link setup request 291 * disc_timeout - send a periodic link setup request
302 * @req: ptr to link request structure 292 * @req: ptr to link request structure
303 * 293 *
@@ -322,7 +312,8 @@ static void disc_timeout(struct tipc_link_req *req)
322 * hold at fast polling rate if don't have any associated nodes, 312 * hold at fast polling rate if don't have any associated nodes,
323 * otherwise hold at slow polling rate 313 * otherwise hold at slow polling rate
324 */ 314 */
325 disc_send_msg(req); 315 tipc_bearer_send(req->bearer, req->buf, &req->dest);
316
326 317
327 req->timer_intv *= 2; 318 req->timer_intv *= 2;
328 if (req->num_nodes) 319 if (req->num_nodes)
@@ -368,7 +359,7 @@ int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest,
368 k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req); 359 k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req);
369 k_start_timer(&req->timer, req->timer_intv); 360 k_start_timer(&req->timer, req->timer_intv);
370 b_ptr->link_req = req; 361 b_ptr->link_req = req;
371 disc_send_msg(req); 362 tipc_bearer_send(req->bearer, req->buf, &req->dest);
372 return 0; 363 return 0;
373} 364}
374 365
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index f80d59f5a161..1e3c33250db3 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -199,7 +199,6 @@ static int enable_media(struct tipc_bearer *tb_ptr)
199 tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_ETH; 199 tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_ETH;
200 tb_ptr->bcast_addr.broadcast = 1; 200 tb_ptr->bcast_addr.broadcast = 1;
201 tb_ptr->mtu = dev->mtu; 201 tb_ptr->mtu = dev->mtu;
202 tb_ptr->blocked = 0;
203 eth_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); 202 eth_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr);
204 return 0; 203 return 0;
205} 204}
@@ -263,20 +262,11 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
263 switch (evt) { 262 switch (evt) {
264 case NETDEV_CHANGE: 263 case NETDEV_CHANGE:
265 if (netif_carrier_ok(dev)) 264 if (netif_carrier_ok(dev))
266 tipc_continue(eb_ptr->bearer); 265 break;
267 else
268 tipc_block_bearer(eb_ptr->bearer);
269 break;
270 case NETDEV_UP:
271 tipc_continue(eb_ptr->bearer);
272 break;
273 case NETDEV_DOWN: 266 case NETDEV_DOWN:
274 tipc_block_bearer(eb_ptr->bearer);
275 break;
276 case NETDEV_CHANGEMTU: 267 case NETDEV_CHANGEMTU:
277 case NETDEV_CHANGEADDR: 268 case NETDEV_CHANGEADDR:
278 tipc_block_bearer(eb_ptr->bearer); 269 tipc_reset_bearer(eb_ptr->bearer);
279 tipc_continue(eb_ptr->bearer);
280 break; 270 break;
281 case NETDEV_UNREGISTER: 271 case NETDEV_UNREGISTER:
282 case NETDEV_CHANGENAME: 272 case NETDEV_CHANGENAME:
diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c
index c13989297464..cbe7fe15cc7c 100644
--- a/net/tipc/ib_media.c
+++ b/net/tipc/ib_media.c
@@ -192,7 +192,6 @@ static int enable_media(struct tipc_bearer *tb_ptr)
192 tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_IB; 192 tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_IB;
193 tb_ptr->bcast_addr.broadcast = 1; 193 tb_ptr->bcast_addr.broadcast = 1;
194 tb_ptr->mtu = dev->mtu; 194 tb_ptr->mtu = dev->mtu;
195 tb_ptr->blocked = 0;
196 ib_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); 195 ib_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr);
197 return 0; 196 return 0;
198} 197}
@@ -256,20 +255,11 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
256 switch (evt) { 255 switch (evt) {
257 case NETDEV_CHANGE: 256 case NETDEV_CHANGE:
258 if (netif_carrier_ok(dev)) 257 if (netif_carrier_ok(dev))
259 tipc_continue(ib_ptr->bearer); 258 break;
260 else
261 tipc_block_bearer(ib_ptr->bearer);
262 break;
263 case NETDEV_UP:
264 tipc_continue(ib_ptr->bearer);
265 break;
266 case NETDEV_DOWN: 259 case NETDEV_DOWN:
267 tipc_block_bearer(ib_ptr->bearer);
268 break;
269 case NETDEV_CHANGEMTU: 260 case NETDEV_CHANGEMTU:
270 case NETDEV_CHANGEADDR: 261 case NETDEV_CHANGEADDR:
271 tipc_block_bearer(ib_ptr->bearer); 262 tipc_reset_bearer(ib_ptr->bearer);
272 tipc_continue(ib_ptr->bearer);
273 break; 263 break;
274 case NETDEV_UNREGISTER: 264 case NETDEV_UNREGISTER:
275 case NETDEV_CHANGENAME: 265 case NETDEV_CHANGENAME:
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 69cd9bf3f561..fd340ad742ea 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -790,8 +790,7 @@ int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf)
790 return link_send_long_buf(l_ptr, buf); 790 return link_send_long_buf(l_ptr, buf);
791 791
792 /* Packet can be queued or sent. */ 792 /* Packet can be queued or sent. */
793 if (likely(!tipc_bearer_blocked(l_ptr->b_ptr) && 793 if (likely(!link_congested(l_ptr))) {
794 !link_congested(l_ptr))) {
795 link_add_to_outqueue(l_ptr, buf, msg); 794 link_add_to_outqueue(l_ptr, buf, msg);
796 795
797 tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); 796 tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr);
@@ -957,14 +956,13 @@ static int link_send_buf_fast(struct tipc_link *l_ptr, struct sk_buff *buf,
957 956
958 if (likely(!link_congested(l_ptr))) { 957 if (likely(!link_congested(l_ptr))) {
959 if (likely(msg_size(msg) <= l_ptr->max_pkt)) { 958 if (likely(msg_size(msg) <= l_ptr->max_pkt)) {
960 if (likely(!tipc_bearer_blocked(l_ptr->b_ptr))) { 959 link_add_to_outqueue(l_ptr, buf, msg);
961 link_add_to_outqueue(l_ptr, buf, msg); 960 tipc_bearer_send(l_ptr->b_ptr, buf,
962 tipc_bearer_send(l_ptr->b_ptr, buf, 961 &l_ptr->media_addr);
963 &l_ptr->media_addr); 962 l_ptr->unacked_window = 0;
964 l_ptr->unacked_window = 0; 963 return res;
965 return res; 964 }
966 } 965 else
967 } else
968 *used_max_pkt = l_ptr->max_pkt; 966 *used_max_pkt = l_ptr->max_pkt;
969 } 967 }
970 return tipc_link_send_buf(l_ptr, buf); /* All other cases */ 968 return tipc_link_send_buf(l_ptr, buf); /* All other cases */
@@ -1013,8 +1011,7 @@ exit:
1013 } 1011 }
1014 1012
1015 /* Exit if link (or bearer) is congested */ 1013 /* Exit if link (or bearer) is congested */
1016 if (link_congested(l_ptr) || 1014 if (link_congested(l_ptr)) {
1017 tipc_bearer_blocked(l_ptr->b_ptr)) {
1018 res = link_schedule_port(l_ptr, 1015 res = link_schedule_port(l_ptr,
1019 sender->ref, res); 1016 sender->ref, res);
1020 goto exit; 1017 goto exit;
@@ -1281,9 +1278,6 @@ void tipc_link_push_queue(struct tipc_link *l_ptr)
1281{ 1278{
1282 u32 res; 1279 u32 res;
1283 1280
1284 if (tipc_bearer_blocked(l_ptr->b_ptr))
1285 return;
1286
1287 do { 1281 do {
1288 res = tipc_link_push_packet(l_ptr); 1282 res = tipc_link_push_packet(l_ptr);
1289 } while (!res); 1283 } while (!res);
@@ -1370,26 +1364,15 @@ void tipc_link_retransmit(struct tipc_link *l_ptr, struct sk_buff *buf,
1370 1364
1371 msg = buf_msg(buf); 1365 msg = buf_msg(buf);
1372 1366
1373 if (tipc_bearer_blocked(l_ptr->b_ptr)) { 1367 /* Detect repeated retransmit failures */
1374 if (l_ptr->retransm_queue_size == 0) { 1368 if (l_ptr->last_retransmitted == msg_seqno(msg)) {
1375 l_ptr->retransm_queue_head = msg_seqno(msg); 1369 if (++l_ptr->stale_count > 100) {
1376 l_ptr->retransm_queue_size = retransmits; 1370 link_retransmit_failure(l_ptr, buf);
1377 } else { 1371 return;
1378 pr_err("Unexpected retransmit on link %s (qsize=%d)\n",
1379 l_ptr->name, l_ptr->retransm_queue_size);
1380 } 1372 }
1381 return;
1382 } else { 1373 } else {
1383 /* Detect repeated retransmit failures on unblocked bearer */ 1374 l_ptr->last_retransmitted = msg_seqno(msg);
1384 if (l_ptr->last_retransmitted == msg_seqno(msg)) { 1375 l_ptr->stale_count = 1;
1385 if (++l_ptr->stale_count > 100) {
1386 link_retransmit_failure(l_ptr, buf);
1387 return;
1388 }
1389 } else {
1390 l_ptr->last_retransmitted = msg_seqno(msg);
1391 l_ptr->stale_count = 1;
1392 }
1393 } 1376 }
1394 1377
1395 while (retransmits && (buf != l_ptr->next_out) && buf) { 1378 while (retransmits && (buf != l_ptr->next_out) && buf) {
@@ -1861,12 +1844,6 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ,
1861 skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg)); 1844 skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg));
1862 buf->priority = TC_PRIO_CONTROL; 1845 buf->priority = TC_PRIO_CONTROL;
1863 1846
1864 /* Defer message if bearer is already blocked */
1865 if (tipc_bearer_blocked(l_ptr->b_ptr)) {
1866 l_ptr->proto_msg_queue = buf;
1867 return;
1868 }
1869
1870 tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); 1847 tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr);
1871 l_ptr->unacked_window = 0; 1848 l_ptr->unacked_window = 0;
1872 kfree_skb(buf); 1849 kfree_skb(buf);