tipc: fix bug in multicast congestion handling
authorJon Maloy <jon.maloy@ericsson.com>
Tue, 7 Oct 2014 18:12:34 +0000 (14:12 -0400)
committerDavid S. Miller <davem@davemloft.net>
Tue, 7 Oct 2014 18:50:15 +0000 (14:50 -0400)
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>
net/tipc/bcast.c
net/tipc/bcast.h
net/tipc/node.c
net/tipc/node.h

index b2bbe69b25543c5a355286ebb75750c6b5726e1c..b8670bf262e249dea10d463fb3b7d2e926ff747e 100644 (file)
@@ -225,6 +225,17 @@ static void bclink_retransmit_pkt(u32 after, u32 to)
        tipc_link_retransmit(bcl, buf, mod(to - after));
 }
 
+/**
+ * tipc_bclink_wakeup_users - wake up pending users
+ *
+ * Called with no locks taken
+ */
+void tipc_bclink_wakeup_users(void)
+{
+       while (skb_queue_len(&bclink->link.waiting_sks))
+               tipc_sk_rcv(skb_dequeue(&bclink->link.waiting_sks));
+}
+
 /**
  * tipc_bclink_acknowledge - handle acknowledgement of broadcast packets
  * @n_ptr: node that sent acknowledgement info
@@ -300,7 +311,8 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
                bclink_set_last_sent();
        }
        if (unlikely(released && !skb_queue_empty(&bcl->waiting_sks)))
-               bclink->node.action_flags |= TIPC_WAKEUP_USERS;
+               n_ptr->action_flags |= TIPC_WAKEUP_BCAST_USERS;
+
 exit:
        tipc_bclink_unlock();
 }
index 4875d9536aee7a98ea523b895b3be6475529d7bd..e7b0f85a82bc82a19573b0f3f4158814ba42b7bd 100644 (file)
@@ -99,5 +99,5 @@ int  tipc_bclink_set_queue_limits(u32 limit);
 void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action);
 uint  tipc_bclink_get_mtu(void);
 int tipc_bclink_xmit(struct sk_buff *buf);
-
+void tipc_bclink_wakeup_users(void);
 #endif
index 17e6378c4dfe479790d085916cb5bfe40b445ae9..90cee4a6fce49450a0f83cca53fcf663ebea8148 100644 (file)
@@ -552,6 +552,7 @@ void tipc_node_unlock(struct tipc_node *node)
        LIST_HEAD(conn_sks);
        struct sk_buff_head waiting_sks;
        u32 addr = 0;
+       unsigned int flags = node->action_flags;
 
        if (likely(!node->action_flags)) {
                spin_unlock_bh(&node->lock);
@@ -572,6 +573,7 @@ void tipc_node_unlock(struct tipc_node *node)
                node->action_flags &= ~TIPC_NOTIFY_NODE_UP;
                addr = node->addr;
        }
+       node->action_flags &= ~TIPC_WAKEUP_BCAST_USERS;
        spin_unlock_bh(&node->lock);
 
        while (!skb_queue_empty(&waiting_sks))
@@ -583,6 +585,9 @@ void tipc_node_unlock(struct tipc_node *node)
        if (!list_empty(&nsub_list))
                tipc_nodesub_notify(&nsub_list);
 
+       if (flags & TIPC_WAKEUP_BCAST_USERS)
+               tipc_bclink_wakeup_users();
+
        if (addr)
                tipc_named_node_up(addr);
 }
index 522d6f3157b32cb9aa2d28086700728216e17e81..67513c3c852c41f2d2a89ffc4d1eb22b7e77de91 100644 (file)
@@ -59,7 +59,8 @@ enum {
        TIPC_WAIT_OWN_LINKS_DOWN        = (1 << 2),
        TIPC_NOTIFY_NODE_DOWN           = (1 << 3),
        TIPC_NOTIFY_NODE_UP             = (1 << 4),
-       TIPC_WAKEUP_USERS               = (1 << 5)
+       TIPC_WAKEUP_USERS               = (1 << 5),
+       TIPC_WAKEUP_BCAST_USERS         = (1 << 6)
 };
 
 /**