diff options
Diffstat (limited to 'net/ipv4/tcp_cong.c')
| -rw-r--r-- | net/ipv4/tcp_cong.c | 32 | 
1 files changed, 22 insertions, 10 deletions
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 324c9bcc5456..fde983f6376b 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -189,8 +189,8 @@ void tcp_init_congestion_control(struct sock *sk)  		INET_ECN_dontxmit(sk);  } -static void tcp_reinit_congestion_control(struct sock *sk, -					  const struct tcp_congestion_ops *ca) +void tcp_reinit_congestion_control(struct sock *sk, +				   const struct tcp_congestion_ops *ca)  {  	struct inet_connection_sock *icsk = inet_csk(sk); @@ -333,8 +333,12 @@ out:  	return ret;  } -/* Change congestion control for socket */ -int tcp_set_congestion_control(struct sock *sk, const char *name) +/* Change congestion control for socket. If load is false, then it is the + * responsibility of the caller to call tcp_init_congestion_control or + * tcp_reinit_congestion_control (if the current congestion control was + * already initialized. + */ +int tcp_set_congestion_control(struct sock *sk, const char *name, bool load)  {  	struct inet_connection_sock *icsk = inet_csk(sk);  	const struct tcp_congestion_ops *ca; @@ -344,21 +348,29 @@ int tcp_set_congestion_control(struct sock *sk, const char *name)  		return -EPERM;  	rcu_read_lock(); -	ca = __tcp_ca_find_autoload(name); +	if (!load) +		ca = tcp_ca_find(name); +	else +		ca = __tcp_ca_find_autoload(name);  	/* No change asking for existing value */  	if (ca == icsk->icsk_ca_ops) {  		icsk->icsk_ca_setsockopt = 1;  		goto out;  	} -	if (!ca) +	if (!ca) {  		err = -ENOENT; -	else if (!((ca->flags & TCP_CONG_NON_RESTRICTED) || -		   ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))) +	} else if (!load) { +		icsk->icsk_ca_ops = ca; +		if (!try_module_get(ca->owner)) +			err = -EBUSY; +	} else if (!((ca->flags & TCP_CONG_NON_RESTRICTED) || +		     ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))) {  		err = -EPERM; -	else if (!try_module_get(ca->owner)) +	} else if (!try_module_get(ca->owner)) {  		err = -EBUSY; -	else +	} else {  		tcp_reinit_congestion_control(sk, ca); +	}   out:  	rcu_read_unlock();  	return err;  | 
