blob: 8f1753defa5ca6ab6409bb992e09910d6845536b [file] [log] [blame]
Glauber Costad1a4c0b2011-12-11 21:47:04 +00001#include <net/tcp.h>
2#include <net/tcp_memcontrol.h>
3#include <net/sock.h>
Glauber Costa3dc43e32011-12-11 21:47:05 +00004#include <net/ip.h>
5#include <linux/nsproxy.h>
Glauber Costad1a4c0b2011-12-11 21:47:04 +00006#include <linux/memcontrol.h>
7#include <linux/module.h>
8
9static inline struct tcp_memcontrol *tcp_from_cgproto(struct cg_proto *cg_proto)
10{
11 return container_of(cg_proto, struct tcp_memcontrol, cg_proto);
12}
13
14static void memcg_tcp_enter_memory_pressure(struct sock *sk)
15{
Dan Carpenterc48e0742011-12-15 01:05:10 +000016 if (sk->sk_cgrp->memory_pressure)
Glauber Costad1a4c0b2011-12-11 21:47:04 +000017 *sk->sk_cgrp->memory_pressure = 1;
18}
19EXPORT_SYMBOL(memcg_tcp_enter_memory_pressure);
20
21int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss)
22{
23 /*
24 * The root cgroup does not use res_counters, but rather,
25 * rely on the data already collected by the network
26 * subsystem
27 */
28 struct res_counter *res_parent = NULL;
29 struct cg_proto *cg_proto, *parent_cg;
30 struct tcp_memcontrol *tcp;
31 struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
32 struct mem_cgroup *parent = parent_mem_cgroup(memcg);
Glauber Costa3dc43e32011-12-11 21:47:05 +000033 struct net *net = current->nsproxy->net_ns;
Glauber Costad1a4c0b2011-12-11 21:47:04 +000034
35 cg_proto = tcp_prot.proto_cgroup(memcg);
36 if (!cg_proto)
Tejun Heo6bc10342012-04-01 12:09:55 -070037 return 0;
Glauber Costad1a4c0b2011-12-11 21:47:04 +000038
39 tcp = tcp_from_cgproto(cg_proto);
40
Glauber Costa3dc43e32011-12-11 21:47:05 +000041 tcp->tcp_prot_mem[0] = net->ipv4.sysctl_tcp_mem[0];
42 tcp->tcp_prot_mem[1] = net->ipv4.sysctl_tcp_mem[1];
43 tcp->tcp_prot_mem[2] = net->ipv4.sysctl_tcp_mem[2];
Glauber Costad1a4c0b2011-12-11 21:47:04 +000044 tcp->tcp_memory_pressure = 0;
45
46 parent_cg = tcp_prot.proto_cgroup(parent);
47 if (parent_cg)
48 res_parent = parent_cg->memory_allocated;
49
50 res_counter_init(&tcp->tcp_memory_allocated, res_parent);
51 percpu_counter_init(&tcp->tcp_sockets_allocated, 0);
52
53 cg_proto->enter_memory_pressure = memcg_tcp_enter_memory_pressure;
54 cg_proto->memory_pressure = &tcp->tcp_memory_pressure;
55 cg_proto->sysctl_mem = tcp->tcp_prot_mem;
56 cg_proto->memory_allocated = &tcp->tcp_memory_allocated;
57 cg_proto->sockets_allocated = &tcp->tcp_sockets_allocated;
58 cg_proto->memcg = memcg;
59
Tejun Heo6bc10342012-04-01 12:09:55 -070060 return 0;
Glauber Costad1a4c0b2011-12-11 21:47:04 +000061}
62EXPORT_SYMBOL(tcp_init_cgroup);
63
Li Zefan761b3ef2012-01-31 13:47:36 +080064void tcp_destroy_cgroup(struct cgroup *cgrp)
Glauber Costad1a4c0b2011-12-11 21:47:04 +000065{
66 struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
67 struct cg_proto *cg_proto;
68 struct tcp_memcontrol *tcp;
Glauber Costa3aaabe22011-12-11 21:47:06 +000069 u64 val;
Glauber Costad1a4c0b2011-12-11 21:47:04 +000070
71 cg_proto = tcp_prot.proto_cgroup(memcg);
72 if (!cg_proto)
73 return;
74
75 tcp = tcp_from_cgproto(cg_proto);
76 percpu_counter_destroy(&tcp->tcp_sockets_allocated);
Glauber Costa3aaabe22011-12-11 21:47:06 +000077
Glauber Costa1398eee2012-01-12 02:16:06 +000078 val = res_counter_read_u64(&tcp->tcp_memory_allocated, RES_LIMIT);
Glauber Costa3aaabe22011-12-11 21:47:06 +000079
80 if (val != RESOURCE_MAX)
Ingo Molnarc5905af2012-02-24 08:31:31 +010081 static_key_slow_dec(&memcg_socket_limit_enabled);
Glauber Costad1a4c0b2011-12-11 21:47:04 +000082}
83EXPORT_SYMBOL(tcp_destroy_cgroup);
Glauber Costa3aaabe22011-12-11 21:47:06 +000084
85static int tcp_update_limit(struct mem_cgroup *memcg, u64 val)
86{
87 struct net *net = current->nsproxy->net_ns;
88 struct tcp_memcontrol *tcp;
89 struct cg_proto *cg_proto;
90 u64 old_lim;
91 int i;
92 int ret;
93
94 cg_proto = tcp_prot.proto_cgroup(memcg);
95 if (!cg_proto)
96 return -EINVAL;
97
98 if (val > RESOURCE_MAX)
99 val = RESOURCE_MAX;
100
101 tcp = tcp_from_cgproto(cg_proto);
102
103 old_lim = res_counter_read_u64(&tcp->tcp_memory_allocated, RES_LIMIT);
104 ret = res_counter_set_limit(&tcp->tcp_memory_allocated, val);
105 if (ret)
106 return ret;
107
108 for (i = 0; i < 3; i++)
109 tcp->tcp_prot_mem[i] = min_t(long, val >> PAGE_SHIFT,
110 net->ipv4.sysctl_tcp_mem[i]);
111
112 if (val == RESOURCE_MAX && old_lim != RESOURCE_MAX)
Ingo Molnarc5905af2012-02-24 08:31:31 +0100113 static_key_slow_dec(&memcg_socket_limit_enabled);
Glauber Costa3aaabe22011-12-11 21:47:06 +0000114 else if (old_lim == RESOURCE_MAX && val != RESOURCE_MAX)
Ingo Molnarc5905af2012-02-24 08:31:31 +0100115 static_key_slow_inc(&memcg_socket_limit_enabled);
Glauber Costa3aaabe22011-12-11 21:47:06 +0000116
117 return 0;
118}
119
120static int tcp_cgroup_write(struct cgroup *cont, struct cftype *cft,
121 const char *buffer)
122{
123 struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
124 unsigned long long val;
125 int ret = 0;
126
127 switch (cft->private) {
128 case RES_LIMIT:
129 /* see memcontrol.c */
130 ret = res_counter_memparse_write_strategy(buffer, &val);
131 if (ret)
132 break;
133 ret = tcp_update_limit(memcg, val);
134 break;
135 default:
136 ret = -EINVAL;
137 break;
138 }
139 return ret;
140}
141
142static u64 tcp_read_stat(struct mem_cgroup *memcg, int type, u64 default_val)
143{
144 struct tcp_memcontrol *tcp;
145 struct cg_proto *cg_proto;
146
147 cg_proto = tcp_prot.proto_cgroup(memcg);
148 if (!cg_proto)
149 return default_val;
150
151 tcp = tcp_from_cgproto(cg_proto);
152 return res_counter_read_u64(&tcp->tcp_memory_allocated, type);
153}
154
Glauber Costa5a6dd342011-12-11 21:47:07 +0000155static u64 tcp_read_usage(struct mem_cgroup *memcg)
156{
157 struct tcp_memcontrol *tcp;
158 struct cg_proto *cg_proto;
159
160 cg_proto = tcp_prot.proto_cgroup(memcg);
161 if (!cg_proto)
162 return atomic_long_read(&tcp_memory_allocated) << PAGE_SHIFT;
163
164 tcp = tcp_from_cgproto(cg_proto);
165 return res_counter_read_u64(&tcp->tcp_memory_allocated, RES_USAGE);
166}
167
Glauber Costa3aaabe22011-12-11 21:47:06 +0000168static u64 tcp_cgroup_read(struct cgroup *cont, struct cftype *cft)
169{
170 struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
171 u64 val;
172
173 switch (cft->private) {
174 case RES_LIMIT:
175 val = tcp_read_stat(memcg, RES_LIMIT, RESOURCE_MAX);
176 break;
Glauber Costa5a6dd342011-12-11 21:47:07 +0000177 case RES_USAGE:
178 val = tcp_read_usage(memcg);
179 break;
Glauber Costaffea59e2011-12-11 21:47:08 +0000180 case RES_FAILCNT:
Glauber Costa0850f0f2011-12-11 21:47:09 +0000181 case RES_MAX_USAGE:
182 val = tcp_read_stat(memcg, cft->private, 0);
Glauber Costaffea59e2011-12-11 21:47:08 +0000183 break;
Glauber Costa3aaabe22011-12-11 21:47:06 +0000184 default:
185 BUG();
186 }
187 return val;
188}
189
Glauber Costaffea59e2011-12-11 21:47:08 +0000190static int tcp_cgroup_reset(struct cgroup *cont, unsigned int event)
191{
192 struct mem_cgroup *memcg;
193 struct tcp_memcontrol *tcp;
194 struct cg_proto *cg_proto;
195
196 memcg = mem_cgroup_from_cont(cont);
197 cg_proto = tcp_prot.proto_cgroup(memcg);
198 if (!cg_proto)
199 return 0;
200 tcp = tcp_from_cgproto(cg_proto);
201
202 switch (event) {
Glauber Costa0850f0f2011-12-11 21:47:09 +0000203 case RES_MAX_USAGE:
204 res_counter_reset_max(&tcp->tcp_memory_allocated);
205 break;
Glauber Costaffea59e2011-12-11 21:47:08 +0000206 case RES_FAILCNT:
207 res_counter_reset_failcnt(&tcp->tcp_memory_allocated);
208 break;
209 }
210
211 return 0;
212}
213
Glauber Costa3aaabe22011-12-11 21:47:06 +0000214unsigned long long tcp_max_memory(const struct mem_cgroup *memcg)
215{
216 struct tcp_memcontrol *tcp;
217 struct cg_proto *cg_proto;
218
219 cg_proto = tcp_prot.proto_cgroup((struct mem_cgroup *)memcg);
220 if (!cg_proto)
221 return 0;
222
223 tcp = tcp_from_cgproto(cg_proto);
224 return res_counter_read_u64(&tcp->tcp_memory_allocated, RES_LIMIT);
225}
226
227void tcp_prot_mem(struct mem_cgroup *memcg, long val, int idx)
228{
229 struct tcp_memcontrol *tcp;
230 struct cg_proto *cg_proto;
231
232 cg_proto = tcp_prot.proto_cgroup(memcg);
233 if (!cg_proto)
234 return;
235
236 tcp = tcp_from_cgproto(cg_proto);
237
238 tcp->tcp_prot_mem[idx] = val;
239}
Tejun Heo676f7c82012-04-01 12:09:55 -0700240
241static struct cftype tcp_files[] = {
242 {
243 .name = "kmem.tcp.limit_in_bytes",
244 .write_string = tcp_cgroup_write,
245 .read_u64 = tcp_cgroup_read,
246 .private = RES_LIMIT,
247 },
248 {
249 .name = "kmem.tcp.usage_in_bytes",
250 .read_u64 = tcp_cgroup_read,
251 .private = RES_USAGE,
252 },
253 {
254 .name = "kmem.tcp.failcnt",
255 .private = RES_FAILCNT,
256 .trigger = tcp_cgroup_reset,
257 .read_u64 = tcp_cgroup_read,
258 },
259 {
260 .name = "kmem.tcp.max_usage_in_bytes",
261 .private = RES_MAX_USAGE,
262 .trigger = tcp_cgroup_reset,
263 .read_u64 = tcp_cgroup_read,
264 },
Tejun Heo6bc10342012-04-01 12:09:55 -0700265 { } /* terminate */
Tejun Heo676f7c82012-04-01 12:09:55 -0700266};
Tejun Heo6bc10342012-04-01 12:09:55 -0700267
268static int __init tcp_memcontrol_init(void)
269{
270 WARN_ON(cgroup_add_cftypes(&mem_cgroup_subsys, tcp_files));
271 return 0;
272}
273__initcall(tcp_memcontrol_init);