diff --git a/net/tipc/group.c b/net/tipc/group.c index 74f6d3dac078..0c6a762000b0 100644 --- a/net/tipc/group.c +++ b/net/tipc/group.c @@ -74,7 +74,7 @@ struct tipc_member { u16 window; u16 bc_rcv_nxt; u16 bc_syncpt; - u16 bc_acked; + bool bc_pending; }; struct tipc_group { @@ -316,7 +316,6 @@ static struct tipc_member *tipc_group_create_member(struct tipc_group *grp, m->node = node; m->port = port; m->instance = instance; - m->bc_acked = grp->bc_snd_nxt - 1; ret = tipc_group_add_to_tree(grp, m); if (ret < 0) { kfree(m); @@ -340,9 +339,12 @@ static void tipc_group_delete_member(struct tipc_group *grp, rb_erase(&m->tree_node, &grp->members); grp->member_cnt--; - /* Check if we were waiting for replicast ack from this member */ - if (grp->bc_ackers && less(m->bc_acked, grp->bc_snd_nxt - 1)) - grp->bc_ackers--; + /* If this member owed an ack for the current replicast and it + * was the last one, restore the open state so blocked broadcast + * senders can proceed. + */ + if (grp->bc_ackers && m->bc_pending && !--grp->bc_ackers) + *grp->open = true; list_del_init(&m->list); list_del_init(&m->small_win); @@ -394,7 +396,6 @@ void tipc_group_update_member(struct tipc_member *m, int len) void tipc_group_update_bc_members(struct tipc_group *grp, int len, bool ack) { - u16 prev = grp->bc_snd_nxt - 1; struct tipc_member *m; struct rb_node *n; u16 ackers = 0; @@ -403,8 +404,8 @@ void tipc_group_update_bc_members(struct tipc_group *grp, int len, bool ack) m = container_of(n, struct tipc_member, tree_node); if (tipc_group_is_receiver(m)) { tipc_group_update_member(m, len); - m->bc_acked = prev; ackers++; + m->bc_pending = ack; } } @@ -800,9 +801,9 @@ void tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup, if (!m || !grp->bc_ackers) return; acked = msg_grp_bc_acked(hdr); - if (acked != grp->bc_snd_nxt || m->bc_acked == acked) + if (acked != grp->bc_snd_nxt || !m->bc_pending) return; - m->bc_acked = acked; + m->bc_pending = false; if (--grp->bc_ackers) return; list_del_init(&m->small_win); diff --git a/net/tipc/socket.c b/net/tipc/socket.c index d5d70eb230b5..65cc0c4964b3 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2356,8 +2356,18 @@ static void tipc_sk_filter_rcv(struct sock *sk, struct sk_buff *skb, if (unlikely(!msg_isdata(hdr))) tipc_sk_proto_rcv(sk, &inputq, xmitq); - if (unlikely(grp)) + if (unlikely(grp)) { + bool was_open = tsk->group_is_open; + tipc_group_filter_msg(grp, &inputq, xmitq); + /* A departing member may have held the last outstanding + * replicast ack, which can restore the open state inside + * tipc_group_filter_msg(); wake up senders blocked in + * poll()/write() if the group just became writable. + */ + if (!was_open && tsk->group_is_open) + sk->sk_write_space(sk); + } if (unlikely(!grp) && mtyp == TIPC_MCAST_MSG) tipc_mcast_filter_msg(net, &tsk->mc_method.deferredq, &inputq);