Blame view

net/ipv4/tcp_memcontrol.c 6.59 KB
d1a4c0b37   Glauber Costa   tcp memory pressu...
1
2
3
  #include <net/tcp.h>
  #include <net/tcp_memcontrol.h>
  #include <net/sock.h>
3dc43e3e4   Glauber Costa   per-netns ipv4 sy...
4
5
  #include <net/ip.h>
  #include <linux/nsproxy.h>
d1a4c0b37   Glauber Costa   tcp memory pressu...
6
7
  #include <linux/memcontrol.h>
  #include <linux/module.h>
3aaabe234   Glauber Costa   tcp buffer limita...
8
9
10
  static u64 tcp_cgroup_read(struct cgroup *cont, struct cftype *cft);
  static int tcp_cgroup_write(struct cgroup *cont, struct cftype *cft,
  			    const char *buffer);
ffea59e50   Glauber Costa   Display current t...
11
  static int tcp_cgroup_reset(struct cgroup *cont, unsigned int event);
3aaabe234   Glauber Costa   tcp buffer limita...
12
13
14
15
16
17
18
19
  
  static struct cftype tcp_files[] = {
  	{
  		.name = "kmem.tcp.limit_in_bytes",
  		.write_string = tcp_cgroup_write,
  		.read_u64 = tcp_cgroup_read,
  		.private = RES_LIMIT,
  	},
5a6dd3437   Glauber Costa   Display current t...
20
21
22
23
24
  	{
  		.name = "kmem.tcp.usage_in_bytes",
  		.read_u64 = tcp_cgroup_read,
  		.private = RES_USAGE,
  	},
ffea59e50   Glauber Costa   Display current t...
25
26
27
28
29
30
  	{
  		.name = "kmem.tcp.failcnt",
  		.private = RES_FAILCNT,
  		.trigger = tcp_cgroup_reset,
  		.read_u64 = tcp_cgroup_read,
  	},
0850f0f5c   Glauber Costa   Display maximum t...
31
32
33
34
35
36
  	{
  		.name = "kmem.tcp.max_usage_in_bytes",
  		.private = RES_MAX_USAGE,
  		.trigger = tcp_cgroup_reset,
  		.read_u64 = tcp_cgroup_read,
  	},
3aaabe234   Glauber Costa   tcp buffer limita...
37
  };
d1a4c0b37   Glauber Costa   tcp memory pressu...
38
39
40
41
42
43
44
  static inline struct tcp_memcontrol *tcp_from_cgproto(struct cg_proto *cg_proto)
  {
  	return container_of(cg_proto, struct tcp_memcontrol, cg_proto);
  }
  
  static void memcg_tcp_enter_memory_pressure(struct sock *sk)
  {
c48e074c7   Dan Carpenter   tcp_memcontrol: f...
45
  	if (sk->sk_cgrp->memory_pressure)
d1a4c0b37   Glauber Costa   tcp memory pressu...
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  		*sk->sk_cgrp->memory_pressure = 1;
  }
  EXPORT_SYMBOL(memcg_tcp_enter_memory_pressure);
  
  int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss)
  {
  	/*
  	 * The root cgroup does not use res_counters, but rather,
  	 * rely on the data already collected by the network
  	 * subsystem
  	 */
  	struct res_counter *res_parent = NULL;
  	struct cg_proto *cg_proto, *parent_cg;
  	struct tcp_memcontrol *tcp;
  	struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
  	struct mem_cgroup *parent = parent_mem_cgroup(memcg);
3dc43e3e4   Glauber Costa   per-netns ipv4 sy...
62
  	struct net *net = current->nsproxy->net_ns;
d1a4c0b37   Glauber Costa   tcp memory pressu...
63
64
65
  
  	cg_proto = tcp_prot.proto_cgroup(memcg);
  	if (!cg_proto)
3aaabe234   Glauber Costa   tcp buffer limita...
66
  		goto create_files;
d1a4c0b37   Glauber Costa   tcp memory pressu...
67
68
  
  	tcp = tcp_from_cgproto(cg_proto);
3dc43e3e4   Glauber Costa   per-netns ipv4 sy...
69
70
71
  	tcp->tcp_prot_mem[0] = net->ipv4.sysctl_tcp_mem[0];
  	tcp->tcp_prot_mem[1] = net->ipv4.sysctl_tcp_mem[1];
  	tcp->tcp_prot_mem[2] = net->ipv4.sysctl_tcp_mem[2];
d1a4c0b37   Glauber Costa   tcp memory pressu...
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  	tcp->tcp_memory_pressure = 0;
  
  	parent_cg = tcp_prot.proto_cgroup(parent);
  	if (parent_cg)
  		res_parent = parent_cg->memory_allocated;
  
  	res_counter_init(&tcp->tcp_memory_allocated, res_parent);
  	percpu_counter_init(&tcp->tcp_sockets_allocated, 0);
  
  	cg_proto->enter_memory_pressure = memcg_tcp_enter_memory_pressure;
  	cg_proto->memory_pressure = &tcp->tcp_memory_pressure;
  	cg_proto->sysctl_mem = tcp->tcp_prot_mem;
  	cg_proto->memory_allocated = &tcp->tcp_memory_allocated;
  	cg_proto->sockets_allocated = &tcp->tcp_sockets_allocated;
  	cg_proto->memcg = memcg;
3aaabe234   Glauber Costa   tcp buffer limita...
87
88
89
  create_files:
  	return cgroup_add_files(cgrp, ss, tcp_files,
  				ARRAY_SIZE(tcp_files));
d1a4c0b37   Glauber Costa   tcp memory pressu...
90
91
92
93
94
95
96
97
  }
  EXPORT_SYMBOL(tcp_init_cgroup);
  
  void tcp_destroy_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss)
  {
  	struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
  	struct cg_proto *cg_proto;
  	struct tcp_memcontrol *tcp;
3aaabe234   Glauber Costa   tcp buffer limita...
98
  	u64 val;
d1a4c0b37   Glauber Costa   tcp memory pressu...
99
100
101
102
103
104
105
  
  	cg_proto = tcp_prot.proto_cgroup(memcg);
  	if (!cg_proto)
  		return;
  
  	tcp = tcp_from_cgproto(cg_proto);
  	percpu_counter_destroy(&tcp->tcp_sockets_allocated);
3aaabe234   Glauber Costa   tcp buffer limita...
106

1398eee08   Glauber Costa   net: decrement me...
107
  	val = res_counter_read_u64(&tcp->tcp_memory_allocated, RES_LIMIT);
3aaabe234   Glauber Costa   tcp buffer limita...
108
109
110
  
  	if (val != RESOURCE_MAX)
  		jump_label_dec(&memcg_socket_limit_enabled);
d1a4c0b37   Glauber Costa   tcp memory pressu...
111
112
  }
  EXPORT_SYMBOL(tcp_destroy_cgroup);
3aaabe234   Glauber Costa   tcp buffer limita...
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  
  static int tcp_update_limit(struct mem_cgroup *memcg, u64 val)
  {
  	struct net *net = current->nsproxy->net_ns;
  	struct tcp_memcontrol *tcp;
  	struct cg_proto *cg_proto;
  	u64 old_lim;
  	int i;
  	int ret;
  
  	cg_proto = tcp_prot.proto_cgroup(memcg);
  	if (!cg_proto)
  		return -EINVAL;
  
  	if (val > RESOURCE_MAX)
  		val = RESOURCE_MAX;
  
  	tcp = tcp_from_cgproto(cg_proto);
  
  	old_lim = res_counter_read_u64(&tcp->tcp_memory_allocated, RES_LIMIT);
  	ret = res_counter_set_limit(&tcp->tcp_memory_allocated, val);
  	if (ret)
  		return ret;
  
  	for (i = 0; i < 3; i++)
  		tcp->tcp_prot_mem[i] = min_t(long, val >> PAGE_SHIFT,
  					     net->ipv4.sysctl_tcp_mem[i]);
  
  	if (val == RESOURCE_MAX && old_lim != RESOURCE_MAX)
  		jump_label_dec(&memcg_socket_limit_enabled);
  	else if (old_lim == RESOURCE_MAX && val != RESOURCE_MAX)
  		jump_label_inc(&memcg_socket_limit_enabled);
  
  	return 0;
  }
  
  static int tcp_cgroup_write(struct cgroup *cont, struct cftype *cft,
  			    const char *buffer)
  {
  	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
  	unsigned long long val;
  	int ret = 0;
  
  	switch (cft->private) {
  	case RES_LIMIT:
  		/* see memcontrol.c */
  		ret = res_counter_memparse_write_strategy(buffer, &val);
  		if (ret)
  			break;
  		ret = tcp_update_limit(memcg, val);
  		break;
  	default:
  		ret = -EINVAL;
  		break;
  	}
  	return ret;
  }
  
  static u64 tcp_read_stat(struct mem_cgroup *memcg, int type, u64 default_val)
  {
  	struct tcp_memcontrol *tcp;
  	struct cg_proto *cg_proto;
  
  	cg_proto = tcp_prot.proto_cgroup(memcg);
  	if (!cg_proto)
  		return default_val;
  
  	tcp = tcp_from_cgproto(cg_proto);
  	return res_counter_read_u64(&tcp->tcp_memory_allocated, type);
  }
5a6dd3437   Glauber Costa   Display current t...
183
184
185
186
187
188
189
190
191
192
193
194
  static u64 tcp_read_usage(struct mem_cgroup *memcg)
  {
  	struct tcp_memcontrol *tcp;
  	struct cg_proto *cg_proto;
  
  	cg_proto = tcp_prot.proto_cgroup(memcg);
  	if (!cg_proto)
  		return atomic_long_read(&tcp_memory_allocated) << PAGE_SHIFT;
  
  	tcp = tcp_from_cgproto(cg_proto);
  	return res_counter_read_u64(&tcp->tcp_memory_allocated, RES_USAGE);
  }
3aaabe234   Glauber Costa   tcp buffer limita...
195
196
197
198
199
200
201
202
203
  static u64 tcp_cgroup_read(struct cgroup *cont, struct cftype *cft)
  {
  	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
  	u64 val;
  
  	switch (cft->private) {
  	case RES_LIMIT:
  		val = tcp_read_stat(memcg, RES_LIMIT, RESOURCE_MAX);
  		break;
5a6dd3437   Glauber Costa   Display current t...
204
205
206
  	case RES_USAGE:
  		val = tcp_read_usage(memcg);
  		break;
ffea59e50   Glauber Costa   Display current t...
207
  	case RES_FAILCNT:
0850f0f5c   Glauber Costa   Display maximum t...
208
209
  	case RES_MAX_USAGE:
  		val = tcp_read_stat(memcg, cft->private, 0);
ffea59e50   Glauber Costa   Display current t...
210
  		break;
3aaabe234   Glauber Costa   tcp buffer limita...
211
212
213
214
215
  	default:
  		BUG();
  	}
  	return val;
  }
ffea59e50   Glauber Costa   Display current t...
216
217
218
219
220
221
222
223
224
225
226
227
228
  static int tcp_cgroup_reset(struct cgroup *cont, unsigned int event)
  {
  	struct mem_cgroup *memcg;
  	struct tcp_memcontrol *tcp;
  	struct cg_proto *cg_proto;
  
  	memcg = mem_cgroup_from_cont(cont);
  	cg_proto = tcp_prot.proto_cgroup(memcg);
  	if (!cg_proto)
  		return 0;
  	tcp = tcp_from_cgproto(cg_proto);
  
  	switch (event) {
0850f0f5c   Glauber Costa   Display maximum t...
229
230
231
  	case RES_MAX_USAGE:
  		res_counter_reset_max(&tcp->tcp_memory_allocated);
  		break;
ffea59e50   Glauber Costa   Display current t...
232
233
234
235
236
237
238
  	case RES_FAILCNT:
  		res_counter_reset_failcnt(&tcp->tcp_memory_allocated);
  		break;
  	}
  
  	return 0;
  }
3aaabe234   Glauber Costa   tcp buffer limita...
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
  unsigned long long tcp_max_memory(const struct mem_cgroup *memcg)
  {
  	struct tcp_memcontrol *tcp;
  	struct cg_proto *cg_proto;
  
  	cg_proto = tcp_prot.proto_cgroup((struct mem_cgroup *)memcg);
  	if (!cg_proto)
  		return 0;
  
  	tcp = tcp_from_cgproto(cg_proto);
  	return res_counter_read_u64(&tcp->tcp_memory_allocated, RES_LIMIT);
  }
  
  void tcp_prot_mem(struct mem_cgroup *memcg, long val, int idx)
  {
  	struct tcp_memcontrol *tcp;
  	struct cg_proto *cg_proto;
  
  	cg_proto = tcp_prot.proto_cgroup(memcg);
  	if (!cg_proto)
  		return;
  
  	tcp = tcp_from_cgproto(cg_proto);
  
  	tcp->tcp_prot_mem[idx] = val;
  }