diff --git a/net/tipc/socket.c b/net/tipc/socket.c index d5d70eb230b5..f3c4bccaadc8 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -156,7 +156,8 @@ static int tipc_sk_insert(struct tipc_sock *tsk); static void tipc_sk_remove(struct tipc_sock *tsk); static int __tipc_sendstream(struct socket *sock, struct msghdr *m, size_t dsz); static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz); -static void tipc_sk_push_backlog(struct tipc_sock *tsk, bool nagle_ack); +static void tipc_sk_push_backlog(struct tipc_sock *tsk, bool nagle_ack, + struct sk_buff_head *xmitq); static int tipc_wait_for_connect(struct socket *sock, long *timeo_p); static const struct proto_ops packet_ops; @@ -561,7 +562,7 @@ static void __tipc_shutdown(struct socket *sock, int error) !tsk_conn_cong(tsk))); /* Push out delayed messages if in Nagle mode */ - tipc_sk_push_backlog(tsk, false); + tipc_sk_push_backlog(tsk, false, NULL); /* Remove pending SYN */ __skb_queue_purge(&sk->sk_write_queue); @@ -1268,8 +1269,10 @@ void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq, /* tipc_sk_push_backlog(): send accumulated buffers in socket write queue * when socket is in Nagle mode + * @xmitq: receive output queue, or NULL outside receive context */ -static void tipc_sk_push_backlog(struct tipc_sock *tsk, bool nagle_ack) +static void tipc_sk_push_backlog(struct tipc_sock *tsk, bool nagle_ack, + struct sk_buff_head *xmitq) { struct sk_buff_head *txq = &tsk->sk.sk_write_queue; struct sk_buff *skb = skb_peek_tail(txq); @@ -1311,6 +1314,10 @@ static void tipc_sk_push_backlog(struct tipc_sock *tsk, bool nagle_ack) tsk->pkt_cnt += skb_queue_len(txq); tsk->snt_unacked += tsk->snd_backlog; tsk->snd_backlog = 0; + if (xmitq && in_own_node(net, dnode)) { + skb_queue_splice_tail_init(txq, xmitq); + return; + } rc = tipc_node_xmit(net, txq, dnode, tsk->portid); if (rc == -ELINKCONG) tsk->cong_link_cnt = 1; @@ -1368,7 +1375,7 @@ static void tipc_sk_conn_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb, goto exit; was_cong = tsk_conn_cong(tsk); - tipc_sk_push_backlog(tsk, msg_nagle_ack(hdr)); + tipc_sk_push_backlog(tsk, msg_nagle_ack(hdr), xmitq); tsk->snt_unacked -= msg_conn_ack(hdr); if (tsk->peer_caps & TIPC_BLOCK_FLOWCTL) tsk->snd_win = msg_adv_win(hdr); @@ -2166,7 +2173,7 @@ static void tipc_sk_proto_rcv(struct sock *sk, smp_wmb(); tsk->cong_link_cnt--; wakeup = true; - tipc_sk_push_backlog(tsk, false); + tipc_sk_push_backlog(tsk, false, xmitq); break; case GROUP_PROTOCOL: tipc_group_proto_rcv(grp, &wakeup, hdr, inputq, xmitq); @@ -2257,7 +2264,7 @@ static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb, return false; case TIPC_ESTABLISHED: if (!skb_queue_empty(&sk->sk_write_queue)) - tipc_sk_push_backlog(tsk, false); + tipc_sk_push_backlog(tsk, false, xmitq); /* Accept only connection-based messages sent by peer */ if (likely(con_msg && !err && pport == oport && pnode == onode)) {