Commit b0254613 authored by Jakub Kicinski's avatar Jakub Kicinski Committed by Paolo Abeni
Browse files

tcp: update window_clamp when SO_RCVBUF is set



Commit under Fixes moved recomputing the window clamp to
tcp_measure_rcv_mss() (when scaling_ratio changes).
I suspect it missed the fact that we don't recompute the clamp
when rcvbuf is set. Until scaling_ratio changes we are
stuck with the old window clamp which may be based on
the small initial buffer. scaling_ratio may never change.

Inspired by Eric's recent commit d1361840 ("tcp: fix
SO_RCVLOWAT and RCVBUF autotuning") plumb the user action
thru to TCP and have it update the clamp.

A smaller fix would be to just have tcp_rcvbuf_grow()
adjust the clamp even if SOCK_RCVBUF_LOCK is set.
But IIUC this is what we were trying to get away from
in the first place.

Fixes: a2cbb160 ("tcp: Update window clamping condition")
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
Reviewed-by: default avatarEric Dumazet <edumaze@google.com>
Link: https://patch.msgid.link/20260408001438.129165-1-kuba@kernel.org


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent c7211b6e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -223,6 +223,7 @@ struct proto_ops {
	int		(*sendmsg_locked)(struct sock *sk, struct msghdr *msg,
					  size_t size);
	int		(*set_rcvlowat)(struct sock *sk, int val);
	void		(*set_rcvbuf)(struct sock *sk, int val);
};

#define DECLARE_SOCKADDR(type, dst, src)	\
+1 −0
Original line number Diff line number Diff line
@@ -516,6 +516,7 @@ void tcp_syn_ack_timeout(const struct request_sock *req);
int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
		int flags);
int tcp_set_rcvlowat(struct sock *sk, int val);
void tcp_set_rcvbuf(struct sock *sk, int val);
int tcp_set_window_clamp(struct sock *sk, int val);

static inline void
+9 −0
Original line number Diff line number Diff line
@@ -966,6 +966,8 @@ EXPORT_SYMBOL(sock_set_keepalive);

static void __sock_set_rcvbuf(struct sock *sk, int val)
{
	struct socket *sock = sk->sk_socket;

	/* Ensure val * 2 fits into an int, to prevent max_t() from treating it
	 * as a negative value.
	 */
@@ -983,6 +985,13 @@ static void __sock_set_rcvbuf(struct sock *sk, int val)
	 * we actually used in getsockopt is the most desirable behavior.
	 */
	WRITE_ONCE(sk->sk_rcvbuf, max_t(int, val * 2, SOCK_MIN_RCVBUF));

	if (sock) {
		const struct proto_ops *ops = READ_ONCE(sock->ops);

		if (ops->set_rcvbuf)
			ops->set_rcvbuf(sk, sk->sk_rcvbuf);
	}
}

void sock_set_rcvbuf(struct sock *sk, int val)
+1 −0
Original line number Diff line number Diff line
@@ -1091,6 +1091,7 @@ const struct proto_ops inet_stream_ops = {
	.compat_ioctl	   = inet_compat_ioctl,
#endif
	.set_rcvlowat	   = tcp_set_rcvlowat,
	.set_rcvbuf	   = tcp_set_rcvbuf,
};
EXPORT_SYMBOL(inet_stream_ops);

+5 −0
Original line number Diff line number Diff line
@@ -1858,6 +1858,11 @@ int tcp_set_rcvlowat(struct sock *sk, int val)
	return 0;
}

void tcp_set_rcvbuf(struct sock *sk, int val)
{
	tcp_set_window_clamp(sk, tcp_win_from_space(sk, val));
}

#ifdef CONFIG_MMU
static const struct vm_operations_struct tcp_vm_ops = {
};
Loading