diff options
| author | David S. Miller <davem@davemloft.net> | 2015-02-05 19:00:06 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2015-02-05 19:00:06 -0500 |
| commit | 7d231e3f762b4cbb0d91f284f3aa6d47a8e83e28 (patch) | |
| tree | 1b1e50e705f4ddd3b36a43ac9067538db3e8233f | |
| parent | 4134069f3ea6cd96903e426bd3dfb9bb44165357 (diff) | |
| parent | cb1b728096f54e7408d60fb571944bed00c5b771 (diff) | |
Merge branch 'tipc-next'
Jon Maloy says:
====================
tipc: resolve message disordering problem
When TIPC receives messages from multi-threaded device drivers it may
occasionally deliver messages to their destination sockets in the wrong
order. This happens despite correct resequencing at the link layer,
because the upcall path from link to socket is not protected by any
locks.
These commits solve this problem by introducing an 'input' message
queue in each link, through which messages must be delivered to the
upper layers.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | net/tipc/bcast.c | 121 | ||||
| -rw-r--r-- | net/tipc/bcast.h | 29 | ||||
| -rw-r--r-- | net/tipc/discover.c | 3 | ||||
| -rw-r--r-- | net/tipc/link.c | 301 | ||||
| -rw-r--r-- | net/tipc/link.h | 14 | ||||
| -rw-r--r-- | net/tipc/msg.c | 109 | ||||
| -rw-r--r-- | net/tipc/msg.h | 107 | ||||
| -rw-r--r-- | net/tipc/name_distr.c | 38 | ||||
| -rw-r--r-- | net/tipc/name_distr.h | 2 | ||||
| -rw-r--r-- | net/tipc/name_table.c | 44 | ||||
| -rw-r--r-- | net/tipc/name_table.h | 20 | ||||
| -rw-r--r-- | net/tipc/node.c | 103 | ||||
| -rw-r--r-- | net/tipc/node.h | 22 | ||||
| -rw-r--r-- | net/tipc/socket.c | 382 | ||||
| -rw-r--r-- | net/tipc/socket.h | 8 |
15 files changed, 740 insertions, 563 deletions
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 53f8bf059fec..81b1fef1f5e0 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/tipc/bcast.c: TIPC broadcast code | 2 | * net/tipc/bcast.c: TIPC broadcast code |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2004-2006, 2014, Ericsson AB | 4 | * Copyright (c) 2004-2006, 2014-2015, Ericsson AB |
| 5 | * Copyright (c) 2004, Intel Corporation. | 5 | * Copyright (c) 2004, Intel Corporation. |
| 6 | * Copyright (c) 2005, 2010-2011, Wind River Systems | 6 | * Copyright (c) 2005, 2010-2011, Wind River Systems |
| 7 | * All rights reserved. | 7 | * All rights reserved. |
| @@ -79,6 +79,13 @@ static void tipc_bclink_unlock(struct net *net) | |||
| 79 | tipc_link_reset_all(node); | 79 | tipc_link_reset_all(node); |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | void tipc_bclink_input(struct net *net) | ||
| 83 | { | ||
| 84 | struct tipc_net *tn = net_generic(net, tipc_net_id); | ||
| 85 | |||
| 86 | tipc_sk_mcast_rcv(net, &tn->bclink->arrvq, &tn->bclink->inputq); | ||
| 87 | } | ||
| 88 | |||
| 82 | uint tipc_bclink_get_mtu(void) | 89 | uint tipc_bclink_get_mtu(void) |
| 83 | { | 90 | { |
| 84 | return MAX_PKT_DEFAULT_MCAST; | 91 | return MAX_PKT_DEFAULT_MCAST; |
| @@ -189,10 +196,8 @@ static void bclink_retransmit_pkt(struct tipc_net *tn, u32 after, u32 to) | |||
| 189 | void tipc_bclink_wakeup_users(struct net *net) | 196 | void tipc_bclink_wakeup_users(struct net *net) |
| 190 | { | 197 | { |
| 191 | struct tipc_net *tn = net_generic(net, tipc_net_id); | 198 | struct tipc_net *tn = net_generic(net, tipc_net_id); |
| 192 | struct sk_buff *skb; | ||
| 193 | 199 | ||
| 194 | while ((skb = skb_dequeue(&tn->bclink->link.waiting_sks))) | 200 | tipc_sk_rcv(net, &tn->bclink->link.wakeupq); |
| 195 | tipc_sk_rcv(net, skb); | ||
| 196 | } | 201 | } |
| 197 | 202 | ||
| 198 | /** | 203 | /** |
| @@ -271,9 +276,8 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked) | |||
| 271 | tipc_link_push_packets(tn->bcl); | 276 | tipc_link_push_packets(tn->bcl); |
| 272 | bclink_set_last_sent(net); | 277 | bclink_set_last_sent(net); |
| 273 | } | 278 | } |
| 274 | if (unlikely(released && !skb_queue_empty(&tn->bcl->waiting_sks))) | 279 | if (unlikely(released && !skb_queue_empty(&tn->bcl->wakeupq))) |
| 275 | n_ptr->action_flags |= TIPC_WAKEUP_BCAST_USERS; | 280 | n_ptr->action_flags |= TIPC_WAKEUP_BCAST_USERS; |
| 276 | |||
| 277 | exit: | 281 | exit: |
| 278 | tipc_bclink_unlock(net); | 282 | tipc_bclink_unlock(net); |
| 279 | } | 283 | } |
| @@ -283,10 +287,11 @@ exit: | |||
| 283 | * | 287 | * |
| 284 | * RCU and node lock set | 288 | * RCU and node lock set |
| 285 | */ | 289 | */ |
| 286 | void tipc_bclink_update_link_state(struct net *net, struct tipc_node *n_ptr, | 290 | void tipc_bclink_update_link_state(struct tipc_node *n_ptr, |
| 287 | u32 last_sent) | 291 | u32 last_sent) |
| 288 | { | 292 | { |
| 289 | struct sk_buff *buf; | 293 | struct sk_buff *buf; |
| 294 | struct net *net = n_ptr->net; | ||
| 290 | struct tipc_net *tn = net_generic(net, tipc_net_id); | 295 | struct tipc_net *tn = net_generic(net, tipc_net_id); |
| 291 | 296 | ||
| 292 | /* Ignore "stale" link state info */ | 297 | /* Ignore "stale" link state info */ |
| @@ -317,7 +322,7 @@ void tipc_bclink_update_link_state(struct net *net, struct tipc_node *n_ptr, | |||
| 317 | struct sk_buff *skb = skb_peek(&n_ptr->bclink.deferred_queue); | 322 | struct sk_buff *skb = skb_peek(&n_ptr->bclink.deferred_queue); |
| 318 | u32 to = skb ? buf_seqno(skb) - 1 : n_ptr->bclink.last_sent; | 323 | u32 to = skb ? buf_seqno(skb) - 1 : n_ptr->bclink.last_sent; |
| 319 | 324 | ||
| 320 | tipc_msg_init(net, msg, BCAST_PROTOCOL, STATE_MSG, | 325 | tipc_msg_init(tn->own_addr, msg, BCAST_PROTOCOL, STATE_MSG, |
| 321 | INT_H_SIZE, n_ptr->addr); | 326 | INT_H_SIZE, n_ptr->addr); |
| 322 | msg_set_non_seq(msg, 1); | 327 | msg_set_non_seq(msg, 1); |
| 323 | msg_set_mc_netid(msg, tn->net_id); | 328 | msg_set_mc_netid(msg, tn->net_id); |
| @@ -358,7 +363,7 @@ static void bclink_peek_nack(struct net *net, struct tipc_msg *msg) | |||
| 358 | tipc_node_unlock(n_ptr); | 363 | tipc_node_unlock(n_ptr); |
| 359 | } | 364 | } |
| 360 | 365 | ||
| 361 | /* tipc_bclink_xmit - broadcast buffer chain to all nodes in cluster | 366 | /* tipc_bclink_xmit - deliver buffer chain to all nodes in cluster |
| 362 | * and to identified node local sockets | 367 | * and to identified node local sockets |
| 363 | * @net: the applicable net namespace | 368 | * @net: the applicable net namespace |
| 364 | * @list: chain of buffers containing message | 369 | * @list: chain of buffers containing message |
| @@ -373,6 +378,8 @@ int tipc_bclink_xmit(struct net *net, struct sk_buff_head *list) | |||
| 373 | int rc = 0; | 378 | int rc = 0; |
| 374 | int bc = 0; | 379 | int bc = 0; |
| 375 | struct sk_buff *skb; | 380 | struct sk_buff *skb; |
| 381 | struct sk_buff_head arrvq; | ||
| 382 | struct sk_buff_head inputq; | ||
| 376 | 383 | ||
| 377 | /* Prepare clone of message for local node */ | 384 | /* Prepare clone of message for local node */ |
| 378 | skb = tipc_msg_reassemble(list); | 385 | skb = tipc_msg_reassemble(list); |
| @@ -381,7 +388,7 @@ int tipc_bclink_xmit(struct net *net, struct sk_buff_head *list) | |||
| 381 | return -EHOSTUNREACH; | 388 | return -EHOSTUNREACH; |
| 382 | } | 389 | } |
| 383 | 390 | ||
| 384 | /* Broadcast to all other nodes */ | 391 | /* Broadcast to all nodes */ |
| 385 | if (likely(bclink)) { | 392 | if (likely(bclink)) { |
| 386 | tipc_bclink_lock(net); | 393 | tipc_bclink_lock(net); |
| 387 | if (likely(bclink->bcast_nodes.count)) { | 394 | if (likely(bclink->bcast_nodes.count)) { |
| @@ -401,12 +408,15 @@ int tipc_bclink_xmit(struct net *net, struct sk_buff_head *list) | |||
| 401 | if (unlikely(!bc)) | 408 | if (unlikely(!bc)) |
| 402 | __skb_queue_purge(list); | 409 | __skb_queue_purge(list); |
| 403 | 410 | ||
| 404 | /* Deliver message clone */ | 411 | if (unlikely(rc)) { |
| 405 | if (likely(!rc)) | ||
| 406 | tipc_sk_mcast_rcv(net, skb); | ||
| 407 | else | ||
| 408 | kfree_skb(skb); | 412 | kfree_skb(skb); |
| 409 | 413 | return rc; | |
| 414 | } | ||
| 415 | /* Deliver message clone */ | ||
| 416 | __skb_queue_head_init(&arrvq); | ||
| 417 | skb_queue_head_init(&inputq); | ||
| 418 | __skb_queue_tail(&arrvq, skb); | ||
| 419 | tipc_sk_mcast_rcv(net, &arrvq, &inputq); | ||
| 410 | return rc; | 420 | return rc; |
| 411 | } | 421 | } |
| 412 | 422 | ||
| @@ -449,6 +459,9 @@ void tipc_bclink_rcv(struct net *net, struct sk_buff *buf) | |||
| 449 | u32 next_in; | 459 | u32 next_in; |
| 450 | u32 seqno; | 460 | u32 seqno; |
| 451 | int deferred = 0; | 461 | int deferred = 0; |
| 462 | int pos = 0; | ||
| 463 | struct sk_buff *iskb; | ||
| 464 | struct sk_buff_head *arrvq, *inputq; | ||
| 452 | 465 | ||
| 453 | /* Screen out unwanted broadcast messages */ | 466 | /* Screen out unwanted broadcast messages */ |
| 454 | if (msg_mc_netid(msg) != tn->net_id) | 467 | if (msg_mc_netid(msg) != tn->net_id) |
| @@ -485,6 +498,8 @@ void tipc_bclink_rcv(struct net *net, struct sk_buff *buf) | |||
| 485 | /* Handle in-sequence broadcast message */ | 498 | /* Handle in-sequence broadcast message */ |
| 486 | seqno = msg_seqno(msg); | 499 | seqno = msg_seqno(msg); |
| 487 | next_in = mod(node->bclink.last_in + 1); | 500 | next_in = mod(node->bclink.last_in + 1); |
| 501 | arrvq = &tn->bclink->arrvq; | ||
| 502 | inputq = &tn->bclink->inputq; | ||
| 488 | 503 | ||
| 489 | if (likely(seqno == next_in)) { | 504 | if (likely(seqno == next_in)) { |
| 490 | receive: | 505 | receive: |
| @@ -492,20 +507,26 @@ receive: | |||
| 492 | if (likely(msg_isdata(msg))) { | 507 | if (likely(msg_isdata(msg))) { |
| 493 | tipc_bclink_lock(net); | 508 | tipc_bclink_lock(net); |
| 494 | bclink_accept_pkt(node, seqno); | 509 | bclink_accept_pkt(node, seqno); |
| 510 | spin_lock_bh(&inputq->lock); | ||
| 511 | __skb_queue_tail(arrvq, buf); | ||
| 512 | spin_unlock_bh(&inputq->lock); | ||
| 513 | node->action_flags |= TIPC_BCAST_MSG_EVT; | ||
| 495 | tipc_bclink_unlock(net); | 514 | tipc_bclink_unlock(net); |
| 496 | tipc_node_unlock(node); | ||
