Commit 71c48eb8 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by David S. Miller
Browse files

tcp: add tcp_sock_set_keepidle



Add a helper to directly set the TCP_KEEP_IDLE 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 c488aead
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -498,6 +498,7 @@ int tcp_skb_shift(struct sk_buff *to, struct sk_buff *from, int pcount,
		  int shiftlen);

void tcp_sock_set_cork(struct sock *sk, bool on);
int tcp_sock_set_keepidle(struct sock *sk, int val);
void tcp_sock_set_nodelay(struct sock *sk);
void tcp_sock_set_quickack(struct sock *sk, int val);
int tcp_sock_set_syncnt(struct sock *sk, int val);
+34 −15
Original line number Diff line number Diff line
@@ -2901,6 +2901,39 @@ void tcp_sock_set_user_timeout(struct sock *sk, u32 val)
}
EXPORT_SYMBOL(tcp_sock_set_user_timeout);

static int __tcp_sock_set_keepidle(struct sock *sk, int val)
{
	struct tcp_sock *tp = tcp_sk(sk);

	if (val < 1 || val > MAX_TCP_KEEPIDLE)
		return -EINVAL;

	tp->keepalive_time = val * HZ;
	if (sock_flag(sk, SOCK_KEEPOPEN) &&
	    !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
		u32 elapsed = keepalive_time_elapsed(tp);

		if (tp->keepalive_time > elapsed)
			elapsed = tp->keepalive_time - elapsed;
		else
			elapsed = 0;
		inet_csk_reset_keepalive_timer(sk, elapsed);
	}

	return 0;
}

int tcp_sock_set_keepidle(struct sock *sk, int val)
{
	int err;

	lock_sock(sk);
	err = __tcp_sock_set_keepidle(sk, val);
	release_sock(sk);
	return err;
}
EXPORT_SYMBOL(tcp_sock_set_keepidle);

/*
 *	Socket option code for TCP.
 */
@@ -3070,21 +3103,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
		break;

	case TCP_KEEPIDLE:
		if (val < 1 || val > MAX_TCP_KEEPIDLE)
			err = -EINVAL;
		else {
			tp->keepalive_time = val * HZ;
			if (sock_flag(sk, SOCK_KEEPOPEN) &&
			    !((1 << sk->sk_state) &
			      (TCPF_CLOSE | TCPF_LISTEN))) {
				u32 elapsed = keepalive_time_elapsed(tp);
				if (tp->keepalive_time > elapsed)
					elapsed = tp->keepalive_time - elapsed;
				else
					elapsed = 0;
				inet_csk_reset_keepalive_timer(sk, elapsed);
			}
		}
		err = __tcp_sock_set_keepidle(sk, val);
		break;
	case TCP_KEEPINTVL:
		if (val < 1 || val > MAX_TCP_KEEPINTVL)
+1 −4
Original line number Diff line number Diff line
@@ -52,10 +52,7 @@ int rds_tcp_keepalive(struct socket *sock)
	if (ret < 0)
		goto bail;

	ret = kernel_setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE,
				(char *)&keepidle, sizeof(keepidle));
	if (ret < 0)
		goto bail;
	tcp_sock_set_keepidle(sock->sk, keepidle);

	/* KEEPINTVL is the interval between successive probes. We follow
	 * the model in xs_tcp_finish_connecting() and re-use keepidle.
+1 −2
Original line number Diff line number Diff line
@@ -2107,8 +2107,7 @@ static void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt,

	/* TCP Keepalive options */
	sock_set_keepalive(sock->sk);
	kernel_setsockopt(sock, SOL_TCP, TCP_KEEPIDLE,
			(char *)&keepidle, sizeof(keepidle));
	tcp_sock_set_keepidle(sock->sk, keepidle);
	kernel_setsockopt(sock, SOL_TCP, TCP_KEEPINTVL,
			(char *)&keepidle, sizeof(keepidle));
	kernel_setsockopt(sock, SOL_TCP, TCP_KEEPCNT,