From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D3778C433E1 for ; Mon, 18 May 2020 18:19:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B89AD20715 for ; Mon, 18 May 2020 18:19:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1589825954; bh=/BcYTFxhp9faC8o2IxkdEy/uKhITvfBagAlcvm74Qdo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-ID:From; b=meg//jcsfN6wH2oVUkRxr5WihmKp1S+XP0PDShjauxexR0zngvLa/lReMmw/hhsgk BOPtaQCWdi9b7ZOlTDdstbDDxDLABFOk6LRinUcdVX1Kkffo/R4HQfZXcIeHasiVRO s1ZgV8g+YRJSEljuz7OcuaVg/GiA0MFFhuedTjxQ= Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731317AbgERRyi (ORCPT ); Mon, 18 May 2020 13:54:38 -0400 Received: from mail.kernel.org ([198.145.29.99]:59408 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731322AbgERRyg (ORCPT ); Mon, 18 May 2020 13:54:36 -0400 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id D6E0520829; Mon, 18 May 2020 17:54:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1589824475; bh=/BcYTFxhp9faC8o2IxkdEy/uKhITvfBagAlcvm74Qdo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qBkeSgcB4ujzywdCOJyXoqUYlIAcFtx1kxPe7SE26Wb/rSdGddYI1BJ+6aVVN2iQG Amenr+NIESasydMC5fBQb0f3ZronM1GOhc3gbgqPZAAwJmdxEVStxyDEmaQmFnANT3 ffjxxkJdo2gEwkAhad7G2LL5cJy1dne6FleMuXB0= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Eric Dumazet , Soheil Hassas Yeganeh , "David S. Miller" Subject: [PATCH 5.4 026/147] tcp: fix SO_RCVLOWAT hangs with fat skbs Date: Mon, 18 May 2020 19:35:49 +0200 Message-Id: <20200518173517.069991648@linuxfoundation.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200518173513.009514388@linuxfoundation.org> References: <20200518173513.009514388@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: stable-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: stable@vger.kernel.org From: Eric Dumazet [ Upstream commit 24adbc1676af4e134e709ddc7f34cf2adc2131e4 ] We autotune rcvbuf whenever SO_RCVLOWAT is set to account for 100% overhead in tcp_set_rcvlowat() This works well when skb->len/skb->truesize ratio is bigger than 0.5 But if we receive packets with small MSS, we can end up in a situation where not enough bytes are available in the receive queue to satisfy RCVLOWAT setting. As our sk_rcvbuf limit is hit, we send zero windows in ACK packets, preventing remote peer from sending more data. Even autotuning does not help, because it only triggers at the time user process drains the queue. If no EPOLLIN is generated, this can not happen. Note poll() has a similar issue, after commit c7004482e8dc ("tcp: Respect SO_RCVLOWAT in tcp_poll().") Fixes: 03f45c883c6f ("tcp: avoid extra wakeups for SO_RCVLOWAT users") Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/tcp.h | 13 +++++++++++++ net/ipv4/tcp.c | 14 +++++++++++--- net/ipv4/tcp_input.c | 3 ++- 3 files changed, 26 insertions(+), 4 deletions(-) --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1401,6 +1401,19 @@ static inline int tcp_full_space(const s return tcp_win_from_space(sk, READ_ONCE(sk->sk_rcvbuf)); } +/* We provision sk_rcvbuf around 200% of sk_rcvlowat. + * If 87.5 % (7/8) of the space has been consumed, we want to override + * SO_RCVLOWAT constraint, since we are receiving skbs with too small + * len/truesize ratio. + */ +static inline bool tcp_rmem_pressure(const struct sock *sk) +{ + int rcvbuf = READ_ONCE(sk->sk_rcvbuf); + int threshold = rcvbuf - (rcvbuf >> 3); + + return atomic_read(&sk->sk_rmem_alloc) > threshold; +} + extern void tcp_openreq_init_rwin(struct request_sock *req, const struct sock *sk_listener, const struct dst_entry *dst); --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -477,9 +477,17 @@ static void tcp_tx_timestamp(struct sock static inline bool tcp_stream_is_readable(const struct tcp_sock *tp, int target, struct sock *sk) { - return (READ_ONCE(tp->rcv_nxt) - READ_ONCE(tp->copied_seq) >= target) || - (sk->sk_prot->stream_memory_read ? - sk->sk_prot->stream_memory_read(sk) : false); + int avail = READ_ONCE(tp->rcv_nxt) - READ_ONCE(tp->copied_seq); + + if (avail > 0) { + if (avail >= target) + return true; + if (tcp_rmem_pressure(sk)) + return true; + } + if (sk->sk_prot->stream_memory_read) + return sk->sk_prot->stream_memory_read(sk); + return false; } /* --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4751,7 +4751,8 @@ void tcp_data_ready(struct sock *sk) const struct tcp_sock *tp = tcp_sk(sk); int avail = tp->rcv_nxt - tp->copied_seq; - if (avail < sk->sk_rcvlowat && !sock_flag(sk, SOCK_DONE)) + if (avail < sk->sk_rcvlowat && !tcp_rmem_pressure(sk) && + !sock_flag(sk, SOCK_DONE)) return; sk->sk_data_ready(sk);