aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/name_distr.c
diff options
context:
space:
mode:
authorJon Paul Maloy <jon.maloy@ericsson.com>2015-02-05 08:36:41 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-05 19:00:02 -0500
commitc637c1035534867b85b78b453c38c495b58e2c5a (patch)
tree77cd2a48a5b04e43b014da64168a6c1e209a1d40 /net/tipc/name_distr.c
parent94153e36e709e78fc4e1f93dc4e4da785690c7d1 (diff)
tipc: resolve race problem at unicast message reception
TIPC handles message cardinality and sequencing at the link layer, before passing messages upwards to the destination sockets. During the upcall from link to socket no locks are held. It is therefore possible, and we see it happen occasionally, that messages arriving in different threads and delivered in sequence still bypass each other before they reach the destination socket. This must not happen, since it violates the sequentiality guarantee. We solve this by adding a new input buffer queue to the link structure. Arriving messages are added safely to the tail of that queue by the link, while the head of the queue is consumed, also safely, by the receiving socket. Sequentiality is secured per socket by only allowing buffers to be dequeued inside the socket lock. Since there may be multiple simultaneous readers of the queue, we use a 'filter' parameter to reduce the risk that they peek the same buffer from the queue, hence also reducing the risk of contention on the receiving socket locks. This solves the sequentiality problem, and seems to cause no measurable performance degradation. A nice side effect of this change is that lock handling in the functions tipc_rcv() and tipc_bcast_rcv() now becomes uniform, something that will enable future simplifications of those functions. 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/name_distr.c')
-rw-r--r--net/tipc/name_distr.c33
1 files changed, 21 insertions, 12 deletions
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index dd8564cd9dbb..fcb07915aaac 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -381,25 +381,34 @@ void tipc_named_process_backlog(struct net *net)
381} 381}
382 382
383/** 383/**
384 * tipc_named_rcv - process name table update message sent by another node 384 * tipc_named_rcv - process name table update messages sent by another node
385 */ 385 */
386void tipc_named_rcv(struct net *net, struct sk_buff *buf) 386void tipc_named_rcv(struct net *net, struct sk_buff_head *inputq)
387{ 387{
388 struct tipc_net *tn = net_generic(net, tipc_net_id); 388 struct tipc_net *tn = net_generic(net, tipc_net_id);
389 struct tipc_msg *msg = buf_msg(buf); 389 struct tipc_msg *msg;
390 struct distr_item *item = (struct distr_item *)msg_data(msg); 390 struct distr_item *item;
391 u32 count = msg_data_sz(msg) / ITEM_SIZE; 391 uint count;
392 u32 node = msg_orignode(msg); 392 u32 node;
393 struct sk_buff *skb;
394 int mtype;
393 395
394 spin_lock_bh(&tn->nametbl_lock); 396 spin_lock_bh(&tn->nametbl_lock);
395 while (count--) { 397 for (skb = skb_dequeue(inputq); skb; skb = skb_dequeue(inputq)) {
396 if (!tipc_update_nametbl(net, item, node, msg_type(msg))) 398 msg = buf_msg(skb);
397 tipc_named_add_backlog(item, msg_type(msg), node); 399 mtype = msg_type(msg);
398 item++; 400 item = (struct distr_item *)msg_data(msg);
401 count = msg_data_sz(msg) / ITEM_SIZE;
402 node = msg_orignode(msg);
403 while (count--) {
404 if (!tipc_update_nametbl(net, item, node, mtype))
405 tipc_named_add_backlog(item, mtype, node);
406 item++;
407 }
408 kfree_skb(skb);
409 tipc_named_process_backlog(net);
399 } 410 }
400 tipc_named_process_backlog(net);
401 spin_unlock_bh(&tn->nametbl_lock); 411 spin_unlock_bh(&tn->nametbl_lock);
402 kfree_skb(buf);
403} 412}
404 413
405/** 414/**