Skip to content

Commit f9c935d

Browse files
Jon Maloydavem330
authored andcommitted
tipc: fix problems with multipoint-to-point flow control
In commit 04d7b57 ("tipc: add multipoint-to-point flow control") we introduced a protocol for preventing buffer overflow when many group members try to simultaneously send messages to the same receiving member. Stress test of this mechanism has revealed a couple of related bugs: - When the receiving member receives an advertisement REMIT message from one of the senders, it will sometimes prematurely activate a pending member and send it the remitted advertisement, although the upper limit for active senders has been reached. This leads to accumulation of illegal advertisements, and eventually to messages being dropped because of receive buffer overflow. - When the receiving member leaves REMITTED state while a received message is being read, we miss to look at the pending queue, to activate the oldest pending peer. This leads to some pending senders being starved out, and never getting the opportunity to profit from the remitted advertisement. We fix the former in the function tipc_group_proto_rcv() by returning directly from the function once it becomes clear that the remitting peer cannot leave REMITTED state at that point. We fix the latter in the function tipc_group_update_rcv_win() by looking up and activate the longest pending peer when it becomes clear that the remitting peer now can leave REMITTED state. Signed-off-by: Jon Maloy <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 71891e2 commit f9c935d

File tree

1 file changed

+18
-4
lines changed

1 file changed

+18
-4
lines changed

net/tipc/group.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ static void tipc_group_proto_xmit(struct tipc_group *grp, struct tipc_member *m,
109109
static void tipc_group_decr_active(struct tipc_group *grp,
110110
struct tipc_member *m)
111111
{
112-
if (m->state == MBR_ACTIVE || m->state == MBR_RECLAIMING)
112+
if (m->state == MBR_ACTIVE || m->state == MBR_RECLAIMING ||
113+
m->state == MBR_REMITTED)
113114
grp->active_cnt--;
114115
}
115116

@@ -562,7 +563,7 @@ void tipc_group_update_rcv_win(struct tipc_group *grp, int blks, u32 node,
562563
int max_active = grp->max_active;
563564
int reclaim_limit = max_active * 3 / 4;
564565
int active_cnt = grp->active_cnt;
565-
struct tipc_member *m, *rm;
566+
struct tipc_member *m, *rm, *pm;
566567

567568
m = tipc_group_find_member(grp, node, port);
568569
if (!m)
@@ -605,6 +606,17 @@ void tipc_group_update_rcv_win(struct tipc_group *grp, int blks, u32 node,
605606
pr_warn_ratelimited("Rcv unexpected msg after REMIT\n");
606607
tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
607608
}
609+
grp->active_cnt--;
610+
list_del_init(&m->list);
611+
if (list_empty(&grp->pending))
612+
return;
613+
614+
/* Set oldest pending member to active and advertise */
615+
pm = list_first_entry(&grp->pending, struct tipc_member, list);
616+
pm->state = MBR_ACTIVE;
617+
list_move_tail(&pm->list, &grp->active);
618+
grp->active_cnt++;
619+
tipc_group_proto_xmit(grp, pm, GRP_ADV_MSG, xmitq);
608620
break;
609621
case MBR_RECLAIMING:
610622
case MBR_DISCOVERED:
@@ -742,14 +754,14 @@ void tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup,
742754
if (!m || m->state != MBR_RECLAIMING)
743755
return;
744756

745-
list_del_init(&m->list);
746-
grp->active_cnt--;
747757
remitted = msg_grp_remitted(hdr);
748758

749759
/* Messages preceding the REMIT still in receive queue */
750760
if (m->advertised > remitted) {
751761
m->state = MBR_REMITTED;
752762
in_flight = m->advertised - remitted;
763+
m->advertised = ADV_IDLE + in_flight;
764+
return;
753765
}
754766
/* All messages preceding the REMIT have been read */
755767
if (m->advertised <= remitted) {
@@ -761,6 +773,8 @@ void tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup,
761773
tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
762774

763775
m->advertised = ADV_IDLE + in_flight;
776+
grp->active_cnt--;
777+
list_del_init(&m->list);
764778

765779
/* Set oldest pending member to active and advertise */
766780
if (list_empty(&grp->pending))

0 commit comments

Comments
 (0)