diff options
Diffstat (limited to 'net/ipv4/sysctl_net_ipv4.c')
| -rw-r--r-- | net/ipv4/sysctl_net_ipv4.c | 69 | 
1 files changed, 60 insertions, 9 deletions
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 69fd7201129..4aa7e9dc0cb 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -14,6 +14,7 @@  #include <linux/init.h>  #include <linux/slab.h>  #include <linux/nsproxy.h> +#include <linux/swap.h>  #include <net/snmp.h>  #include <net/icmp.h>  #include <net/ip.h> @@ -23,6 +24,7 @@  #include <net/cipso_ipv4.h>  #include <net/inet_frag.h>  #include <net/ping.h> +#include <net/tcp_memcontrol.h>  static int zero;  static int tcp_retr1_max = 255; @@ -73,7 +75,7 @@ static int ipv4_local_port_range(ctl_table *table, int write,  } -void inet_get_ping_group_range_table(struct ctl_table *table, gid_t *low, gid_t *high) +static void inet_get_ping_group_range_table(struct ctl_table *table, gid_t *low, gid_t *high)  {  	gid_t *data = table->data;  	unsigned seq; @@ -86,7 +88,7 @@ void inet_get_ping_group_range_table(struct ctl_table *table, gid_t *low, gid_t  }  /* Update system visible IP port range */ -static void set_ping_group_range(struct ctl_table *table, int range[2]) +static void set_ping_group_range(struct ctl_table *table, gid_t range[2])  {  	gid_t *data = table->data;  	write_seqlock(&sysctl_local_ports.lock); @@ -174,6 +176,49 @@ static int proc_allowed_congestion_control(ctl_table *ctl,  	return ret;  } +static int ipv4_tcp_mem(ctl_table *ctl, int write, +			   void __user *buffer, size_t *lenp, +			   loff_t *ppos) +{ +	int ret; +	unsigned long vec[3]; +	struct net *net = current->nsproxy->net_ns; +#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM +	struct mem_cgroup *memcg; +#endif + +	ctl_table tmp = { +		.data = &vec, +		.maxlen = sizeof(vec), +		.mode = ctl->mode, +	}; + +	if (!write) { +		ctl->data = &net->ipv4.sysctl_tcp_mem; +		return proc_doulongvec_minmax(ctl, write, buffer, lenp, ppos); +	} + +	ret = proc_doulongvec_minmax(&tmp, write, buffer, lenp, ppos); +	if (ret) +		return ret; + +#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM +	rcu_read_lock(); +	memcg = mem_cgroup_from_task(current); + +	tcp_prot_mem(memcg, vec[0], 0); +	tcp_prot_mem(memcg, vec[1], 1); +	tcp_prot_mem(memcg, vec[2], 2); +	rcu_read_unlock(); +#endif + +	net->ipv4.sysctl_tcp_mem[0] = vec[0]; +	net->ipv4.sysctl_tcp_mem[1] = vec[1]; +	net->ipv4.sysctl_tcp_mem[2] = vec[2]; + +	return 0; +} +  static struct ctl_table ipv4_table[] = {  	{  		.procname	= "tcp_timestamps", @@ -433,13 +478,6 @@ static struct ctl_table ipv4_table[] = {  		.proc_handler	= proc_dointvec  	},  	{ -		.procname	= "tcp_mem", -		.data		= &sysctl_tcp_mem, -		.maxlen		= sizeof(sysctl_tcp_mem), -		.mode		= 0644, -		.proc_handler	= proc_doulongvec_minmax -	}, -	{  		.procname	= "tcp_wmem",  		.data		= &sysctl_tcp_wmem,  		.maxlen		= sizeof(sysctl_tcp_wmem), @@ -721,6 +759,12 @@ static struct ctl_table ipv4_net_table[] = {  		.mode		= 0644,  		.proc_handler	= ipv4_ping_group_range,  	}, +	{ +		.procname	= "tcp_mem", +		.maxlen		= sizeof(init_net.ipv4.sysctl_tcp_mem), +		.mode		= 0644, +		.proc_handler	= ipv4_tcp_mem, +	},  	{ }  }; @@ -734,6 +778,7 @@ EXPORT_SYMBOL_GPL(net_ipv4_ctl_path);  static __net_init int ipv4_sysctl_init_net(struct net *net)  {  	struct ctl_table *table; +	unsigned long limit;  	table = ipv4_net_table;  	if (!net_eq(net, &init_net)) { @@ -769,6 +814,12 @@ static __net_init int ipv4_sysctl_init_net(struct net *net)  	net->ipv4.sysctl_rt_cache_rebuild_count = 4; +	limit = nr_free_buffer_pages() / 8; +	limit = max(limit, 128UL); +	net->ipv4.sysctl_tcp_mem[0] = limit / 4 * 3; +	net->ipv4.sysctl_tcp_mem[1] = limit; +	net->ipv4.sysctl_tcp_mem[2] = net->ipv4.sysctl_tcp_mem[0] * 2; +  	net->ipv4.ipv4_hdr = register_net_sysctl_table(net,  			net_ipv4_ctl_path, table);  	if (net->ipv4.ipv4_hdr == NULL)  |