Commit 26cfabf9 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by David S. Miller
Browse files

net: add sock_set_rcvbuf



Add a helper to directly set the SO_RCVBUFFORCE sockopt from kernel space
without going through a fake uaccess.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ce3d9544
Loading
Loading
Loading
Loading
+1 −6
Original line number Diff line number Diff line
@@ -1180,7 +1180,6 @@ static int sctp_listen_for_all(void)
	struct socket *sock = NULL;
	int result = -EINVAL;
	struct connection *con = nodeid2con(0, GFP_NOFS);
	int bufsize = NEEDED_RMEM;
	int one = 1;

	if (!con)
@@ -1195,11 +1194,7 @@ static int sctp_listen_for_all(void)
		goto out;
	}

	result = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVBUFFORCE,
				 (char *)&bufsize, sizeof(bufsize));
	if (result)
		log_print("Error increasing buffer space on socket %d", result);

	sock_set_rcvbuf(sock->sk, NEEDED_RMEM);
	result = kernel_setsockopt(sock, SOL_SCTP, SCTP_NODELAY, (char *)&one,
				   sizeof(one));
	if (result < 0)
+1 −0
Original line number Diff line number Diff line
@@ -2693,6 +2693,7 @@ void sock_enable_timestamps(struct sock *sk);
void sock_no_linger(struct sock *sk);
void sock_set_keepalive(struct sock *sk);
void sock_set_priority(struct sock *sk, u32 priority);
void sock_set_rcvbuf(struct sock *sk, int val);
void sock_set_reuseaddr(struct sock *sk);
void sock_set_sndtimeo(struct sock *sk, s64 secs);

+32 −27
Original line number Diff line number Diff line
@@ -789,6 +789,35 @@ void sock_set_keepalive(struct sock *sk)
}
EXPORT_SYMBOL(sock_set_keepalive);

static void __sock_set_rcvbuf(struct sock *sk, int val)
{
	/* Ensure val * 2 fits into an int, to prevent max_t() from treating it
	 * as a negative value.
	 */
	val = min_t(int, val, INT_MAX / 2);
	sk->sk_userlocks |= SOCK_RCVBUF_LOCK;

	/* We double it on the way in to account for "struct sk_buff" etc.
	 * overhead.   Applications assume that the SO_RCVBUF setting they make
	 * will allow that much actual data to be received on that socket.
	 *
	 * Applications are unaware that "struct sk_buff" and other overheads
	 * allocate from the receive buffer during socket buffer allocation.
	 *
	 * And after considering the possible alternatives, returning the value
	 * we actually used in getsockopt is the most desirable behavior.
	 */
	WRITE_ONCE(sk->sk_rcvbuf, max_t(int, val * 2, SOCK_MIN_RCVBUF));
}

void sock_set_rcvbuf(struct sock *sk, int val)
{
	lock_sock(sk);
	__sock_set_rcvbuf(sk, val);
	release_sock(sk);
}
EXPORT_SYMBOL(sock_set_rcvbuf);

/*
 *	This is meant for all protocols to use and covers goings on
 *	at the socket level. Everything here is generic.
@@ -885,30 +914,7 @@ set_sndbuf:
		 * play 'guess the biggest size' games. RCVBUF/SNDBUF
		 * are treated in BSD as hints
		 */
		val = min_t(u32, val, sysctl_rmem_max);
set_rcvbuf:
		/* Ensure val * 2 fits into an int, to prevent max_t()
		 * from treating it as a negative value.
		 */
		val = min_t(int, val, INT_MAX / 2);
		sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
		/*
		 * We double it on the way in to account for
		 * "struct sk_buff" etc. overhead.   Applications
		 * assume that the SO_RCVBUF setting they make will
		 * allow that much actual data to be received on that
		 * socket.
		 *
		 * Applications are unaware that "struct sk_buff" and
		 * other overheads allocate from the receive buffer
		 * during socket buffer allocation.
		 *
		 * And after considering the possible alternatives,
		 * returning the value we actually used in getsockopt
		 * is the most desirable behavior.
		 */
		WRITE_ONCE(sk->sk_rcvbuf,
			   max_t(int, val * 2, SOCK_MIN_RCVBUF));
		__sock_set_rcvbuf(sk, min_t(u32, val, sysctl_rmem_max));
		break;

	case SO_RCVBUFFORCE:
@@ -920,9 +926,8 @@ set_rcvbuf:
		/* No negative values (to prevent underflow, as val will be
		 * multiplied by 2).
		 */
		if (val < 0)
			val = 0;
		goto set_rcvbuf;
		__sock_set_rcvbuf(sk, max(val, 0));
		break;

	case SO_KEEPALIVE:
		if (sk->sk_prot->keepalive)