A little ugly, but I have no better idea at the moment.
Acked-by: Jon


> -----Original Message-----
> From: Tuong Lien <tuong.t.l...@dektech.com.au>
> Sent: 25-Nov-19 23:07
> To: tipc-discussion@lists.sourceforge.net; Jon Maloy 
> <jon.ma...@ericsson.com>; ma...@donjonn.com;
> ying....@windriver.com
> Subject: [PATCH RFC] tipc: fix potential hanging after b/rcast changing
> 
> In commit c55c8edafa91 ("tipc: smooth change between replicast and
> broadcast"), we allow instant switching between replicast and broadcast
> by sending a dummy 'SYN' packet on the last used link to synchronize
> packets on the links. The 'SYN' message is an object of link congestion
> also, so if that happens, a 'SOCK_WAKEUP' will be scheduled to be sent
> back to the socket...
> However, in that commit, we simply use the same socket 'cong_link_cnt'
> counter for both the 'SYN' & normal payload message sending. Therefore,
> if both the replicast & broadcast links are congested, the counter will
> be not updated correctly but overwritten by the latter congestion.
> Later on, when the 'SOCK_WAKEUP' messages are processed, the counter is
> reduced one by one and eventually overflowed. Consequently, further
> activities on the socket will only wait for the false congestion signal
> to disappear but never been met.
> 
> Because sending the 'SYN' message is vital for the mechanism, it should
> be done anyway. This commit fixes the issue by marking the message with
> an error code e.g. 'TIPC_ERR_NO_PORT', so its sending should not face a
> link congestion, there is no need to touch the socket 'cong_link_cnt'
> either. In addition, in the event of any error (e.g. -ENOBUFS), we will
> purge the entire payload message queue and make a return immediately.
> 
> Fixes: c55c8edafa91 ("tipc: smooth change between replicast and broadcast")
> Signed-off-by: Tuong Lien <tuong.t.l...@dektech.com.au>
> ---
>  net/tipc/bcast.c | 24 +++++++++++++++---------
>  1 file changed, 15 insertions(+), 9 deletions(-)
> 
> diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
> index 55aeba681cf4..656ebc79c64e 100644
> --- a/net/tipc/bcast.c
> +++ b/net/tipc/bcast.c
> @@ -305,17 +305,17 @@ static int tipc_rcast_xmit(struct net *net, struct 
> sk_buff_head *pkts,
>   * @skb: socket buffer to copy
>   * @method: send method to be used
>   * @dests: destination nodes for message.
> - * @cong_link_cnt: returns number of encountered congested destination links
>   * Returns 0 if success, otherwise errno
>   */
>  static int tipc_mcast_send_sync(struct net *net, struct sk_buff *skb,
>                               struct tipc_mc_method *method,
> -                             struct tipc_nlist *dests,
> -                             u16 *cong_link_cnt)
> +                             struct tipc_nlist *dests)
>  {
>       struct tipc_msg *hdr, *_hdr;
>       struct sk_buff_head tmpq;
>       struct sk_buff *_skb;
> +     u16 cong_link_cnt;
> +     int rc = 0;
> 
>       /* Is a cluster supporting with new capabilities ? */
>       if (!(tipc_net(net)->capabilities & TIPC_MCAST_RBCTL))
> @@ -343,18 +343,19 @@ static int tipc_mcast_send_sync(struct net *net, struct 
> sk_buff *skb,
>       _hdr = buf_msg(_skb);
>       msg_set_size(_hdr, MCAST_H_SIZE);
>       msg_set_is_rcast(_hdr, !msg_is_rcast(hdr));
> +     msg_set_errcode(_hdr, TIPC_ERR_NO_PORT);
> 
>       __skb_queue_head_init(&tmpq);
>       __skb_queue_tail(&tmpq, _skb);
>       if (method->rcast)
> -             tipc_bcast_xmit(net, &tmpq, cong_link_cnt);
> +             rc = tipc_bcast_xmit(net, &tmpq, &cong_link_cnt);
>       else
> -             tipc_rcast_xmit(net, &tmpq, dests, cong_link_cnt);
> +             rc = tipc_rcast_xmit(net, &tmpq, dests, &cong_link_cnt);
> 
>       /* This queue should normally be empty by now */
>       __skb_queue_purge(&tmpq);
> 
> -     return 0;
> +     return rc;
>  }
> 
>  /* tipc_mcast_xmit - deliver message to indicated destination nodes
> @@ -396,9 +397,14 @@ int tipc_mcast_xmit(struct net *net, struct sk_buff_head 
> *pkts,
>               msg_set_is_rcast(hdr, method->rcast);
> 
>               /* Switch method ? */
> -             if (rcast != method->rcast)
> -                     tipc_mcast_send_sync(net, skb, method,
> -                                          dests, cong_link_cnt);
> +             if (rcast != method->rcast) {
> +                     rc = tipc_mcast_send_sync(net, skb, method, dests);
> +                     if (unlikely(rc)) {
> +                             pr_err("Unable to send SYN: method %d, rc %d\n",
> +                                    rcast, rc);
> +                             goto exit;
> +                     }
> +             }
> 
>               if (method->rcast)
>                       rc = tipc_rcast_xmit(net, pkts, dests, cong_link_cnt);
> --
> 2.13.7


_______________________________________________
tipc-discussion mailing list
tipc-discussion@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tipc-discussion

Reply via email to