aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Maloy <jon.maloy@ericsson.com>2014-10-07 14:12:34 -0400
committerDavid S. Miller <davem@davemloft.net>2014-10-07 14:50:15 -0400
commit908344cdda8039dd5c291e8a1ddd49649dff8c4b (patch)
tree71dc17135653c03a5c6309e873950c5c392b52d2
parent0287587884b15041203b3a362d485e1ab1f24445 (diff)
tipc: fix bug in multicast congestion handling
One aim of commit 50100a5e39461b2a61d6040e73c384766c29975d ("tipc: use pseudo message to wake up sockets after link congestion") was to handle link congestion abatement in a uniform way for both unicast and multicast transmit. However, the latter doesn't work correctly, and has been broken since the referenced commit was applied. If a user now sends a burst of multicast messages that is big enough to cause broadcast link congestion, it will be put to sleep, and not be waked up when the congestion abates as it should be. This has two reasons. First, the flag that is used, TIPC_WAKEUP_USERS, is set correctly, but in the wrong field. Instead of setting it in the 'action_flags' field of the arrival node struct, it is by mistake set in the dummy node struct that is owned by the broadcast link, where it will never tested for. Second, we cannot use the same flag for waking up unicast and multicast users, since the function tipc_node_unlock() needs to pick the wakeup pseudo messages to deliver from different queues. It must hence be able to distinguish between the two cases. This commit solves this problem by adding a new flag TIPC_WAKEUP_BCAST_USERS, and a new function tipc_bclink_wakeup_user(). The latter is to be called by tipc_node_unlock() when the named flag, now set in the correct field, is encountered. v2: using explicit 'unsigned int' declaration instead of 'uint', as per comment from David Miller. Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/tipc/bcast.c14
-rw-r--r--net/tipc/bcast.h2
-rw-r--r--net/tipc/node.c5
-rw-r--r--net/tipc/node.h3
4 files changed, 21 insertions, 3 deletions
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index b2bbe69b2554..b8670bf262e2 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -226,6 +226,17 @@ static void bclink_retransmit_pkt(u32 after, u32 to)
226} 226}
227 227
228/** 228/**
229 * tipc_bclink_wakeup_users - wake up pending users
230 *
231 * Called with no locks taken
232 */
233void tipc_bclink_wakeup_users(void)
234{
235 while (skb_queue_len(&bclink->link.waiting_sks))
236 tipc_sk_rcv(skb_dequeue(&bclink->link.waiting_sks));
237}
238
239/**
229 * tipc_bclink_acknowledge - handle acknowledgement of broadcast packets 240 * tipc_bclink_acknowledge - handle acknowledgement of broadcast packets
230 * @n_ptr: node that sent acknowledgement info 241 * @n_ptr: node that sent acknowledgement info
231 * @acked: broadcast sequence # that has been acknowledged 242 * @acked: broadcast sequence # that has been acknowledged
@@ -300,7 +311,8 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
300 bclink_set_last_sent(); 311 bclink_set_last_sent();
301 } 312 }
302 if (unlikely(released && !skb_queue_empty(&bcl->waiting_sks))) 313 if (unlikely(released && !skb_queue_empty(&bcl->waiting_sks)))
303 bclink->node.action_flags |= TIPC_WAKEUP_USERS; 314 n_ptr->action_flags |= TIPC_WAKEUP_BCAST_USERS;
315
304exit: 316exit:
305 tipc_bclink_unlock(); 317 tipc_bclink_unlock();
306} 318}
diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h
index 4875d9536aee..e7b0f85a82bc 100644
--- a/net/tipc/bcast.h
+++ b/net/tipc/bcast.h
@@ -99,5 +99,5 @@ int tipc_bclink_set_queue_limits(u32 limit);
99void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action); 99void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action);
100uint tipc_bclink_get_mtu(void); 100uint tipc_bclink_get_mtu(void);
101int tipc_bclink_xmit(struct sk_buff *buf); 101int tipc_bclink_xmit(struct sk_buff *buf);
102 102void tipc_bclink_wakeup_users(void);
103#endif 103#endif
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 17e6378c4dfe..90cee4a6fce4 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -552,6 +552,7 @@ void tipc_node_unlock(struct tipc_node *node)
552 LIST_HEAD(conn_sks); 552 LIST_HEAD(conn_sks);
553 struct sk_buff_head waiting_sks; 553 struct sk_buff_head waiting_sks;
554 u32 addr = 0; 554 u32 addr = 0;
555 unsigned int flags = node->action_flags;
555 556
556 if (likely(!node->action_flags)) { 557 if (likely(!node->action_flags)) {
557 spin_unlock_bh(&node->lock); 558 spin_unlock_bh(&node->lock);
@@ -572,6 +573,7 @@ void tipc_node_unlock(struct tipc_node *node)
572 node->action_flags &= ~TIPC_NOTIFY_NODE_UP; 573 node->action_flags &= ~TIPC_NOTIFY_NODE_UP;
573 addr = node->addr; 574 addr = node->addr;
574 } 575 }
576 node->action_flags &= ~TIPC_WAKEUP_BCAST_USERS;
575 spin_unlock_bh(&node->lock); 577 spin_unlock_bh(&node->lock);
576 578
577 while (!skb_queue_empty(&waiting_sks)) 579 while (!skb_queue_empty(&waiting_sks))
@@ -583,6 +585,9 @@ void tipc_node_unlock(struct tipc_node *node)
583 if (!list_empty(&nsub_list)) 585 if (!list_empty(&nsub_list))
584 tipc_nodesub_notify(&nsub_list); 586 tipc_nodesub_notify(&nsub_list);
585 587
588 if (flags & TIPC_WAKEUP_BCAST_USERS)
589 tipc_bclink_wakeup_users();
590
586 if (addr) 591 if (addr)
587 tipc_named_node_up(addr); 592 tipc_named_node_up(addr);
588} 593}
diff --git a/net/tipc/node.h b/net/tipc/node.h
index 522d6f3157b3..67513c3c852c 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -59,7 +59,8 @@ enum {
59 TIPC_WAIT_OWN_LINKS_DOWN = (1 << 2), 59 TIPC_WAIT_OWN_LINKS_DOWN = (1 << 2),
60 TIPC_NOTIFY_NODE_DOWN = (1 << 3), 60 TIPC_NOTIFY_NODE_DOWN = (1 << 3),
61 TIPC_NOTIFY_NODE_UP = (1 << 4), 61 TIPC_NOTIFY_NODE_UP = (1 << 4),
62 TIPC_WAKEUP_USERS = (1 << 5) 62 TIPC_WAKEUP_USERS = (1 << 5),
63 TIPC_WAKEUP_BCAST_USERS = (1 << 6)
63}; 64};
64 65
65/** 66/**