blob: 9481f235803e4ed4347f12b72adddb67fb947a7d [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
Glauber Costa3aaabe22011-12-11 21:47:06 +00009static u64 tcp_cgroup_read(struct cgroup *cont, struct cftype *cft);
10static int tcp_cgroup_write(struct cgroup *cont, struct cftype *cft,
11 const char *buffer);
12
13static struct cftype tcp_files[] = {
14 {
15 .name = "kmem.tcp.limit_in_bytes",
16 .write_string = tcp_cgroup_write,
17 .read_u64 = tcp_cgroup_read,
18 .private = RES_LIMIT,
19 },
Glauber Costa5a6dd342011-12-11 21:47:07 +000020 {
21 .name = "kmem.tcp.usage_in_bytes",
22 .read_u64 = tcp_cgroup_read,
23 .private = RES_USAGE,
24 },
Glauber Costa3aaabe22011-12-11 21:47:06 +000025};
26
Glauber Costad1a4c0b2011-12-11 21:47:04 +000027static inline struct tcp_memcontrol *tcp_from_cgproto(struct cg_proto *cg_proto)
28{
29 return container_of(cg_proto, struct tcp_memcontrol, cg_proto);
30}
31
32static void memcg_tcp_enter_memory_pressure(struct sock *sk)
33{
34 if (!sk->sk_cgrp->memory_pressure)
35 *sk->sk_cgrp->memory_pressure = 1;
36}
37EXPORT_SYMBOL(memcg_tcp_enter_memory_pressure);
38
39int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss)
40{
41 /*
42 * The root cgroup does not use res_counters, but rather,
43 * rely on the data already collected by the network
44 * subsystem
45 */
46 struct res_counter *res_parent = NULL;
47 struct cg_proto *cg_proto, *parent_cg;
48 struct tcp_memcontrol *tcp;
49 struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
50 struct mem_cgroup *parent = parent_mem_cgroup(memcg);
Glauber Costa3dc43e32011-12-11 21:47:05 +000051 struct net *net = current->nsproxy->net_ns;
Glauber Costad1a4c0b2011-12-11 21:47:04 +000052
53 cg_proto = tcp_prot.proto_cgroup(memcg);
54 if (!cg_proto)
Glauber Costa3aaabe22011-12-11 21:47:06 +000055 goto create_files;
Glauber Costad1a4c0b2011-12-11 21:47:04 +000056
57 tcp = tcp_from_cgproto(cg_proto);
58
Glauber Costa3dc43e32011-12-11 21:47:05 +000059 tcp->tcp_prot_mem[0] = net->ipv4.sysctl_tcp_mem[0];
60 tcp->tcp_prot_mem[1] = net->ipv4.sysctl_tcp_mem[1];
61 tcp->tcp_prot_mem[2] = net->ipv4.sysctl_tcp_mem[2];
Glauber Costad1a4c0b2011-12-11 21:47:04 +000062 tcp->tcp_memory_pressure = 0;
63
64 parent_cg = tcp_prot.proto_cgroup(parent);
65 if (parent_cg)
66 res_parent = parent_cg->memory_allocated;
67
68 res_counter_init(&tcp->tcp_memory_allocated, res_parent);
69 percpu_counter_init(&tcp->tcp_sockets_allocated, 0);
70
71 cg_proto->enter_memory_pressure = memcg_tcp_enter_memory_pressure;
72 cg_proto->memory_pressure = &tcp->tcp_memory_pressure;
73 cg_proto->sysctl_mem = tcp->tcp_prot_mem;
74 cg_proto->memory_allocated = &tcp->tcp_memory_allocated;
75 cg_proto->sockets_allocated = &tcp->tcp_sockets_allocated;
76 cg_proto->memcg = memcg;
77
Glauber Costa3aaabe22011-12-11 21:47:06 +000078create_files:
79 return cgroup_add_files(cgrp, ss, tcp_files,
80 ARRAY_SIZE(tcp_files));
Glauber Costad1a4c0b2011-12-11 21:47:04 +000081}
82EXPORT_SYMBOL(tcp_init_cgroup);
83
84void tcp_destroy_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss)
85{
86 struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
87 struct cg_proto *cg_proto;
88 struct tcp_memcontrol *tcp;
Glauber Costa3aaabe22011-12-11 21:47:06 +000089 u64 val;
Glauber Costad1a4c0b2011-12-11 21:47:04 +000090
91 cg_proto = tcp_prot.proto_cgroup(memcg);
92 if (!cg_proto)
93 return;
94
95 tcp = tcp_from_cgproto(cg_proto);
96 percpu_counter_destroy(&tcp->tcp_sockets_allocated);
Glauber Costa3aaabe22011-12-11 21:47:06 +000097
98 val = res_counter_read_u64(&tcp->tcp_memory_allocated, RES_USAGE);
99
100 if (val != RESOURCE_MAX)
101 jump_label_dec(&memcg_socket_limit_enabled);
Glauber Costad1a4c0b2011-12-11 21:47:04 +0000102}
103EXPORT_SYMBOL(tcp_destroy_cgroup);
Glauber Costa3aaabe22011-12-11 21:47:06 +0000104
105static int tcp_update_limit(struct mem_cgroup *memcg, u64 val)
106{
107 struct net *net = current->nsproxy->net_ns;
108 struct tcp_memcontrol *tcp;
109 struct cg_proto *cg_proto;
110 u64 old_lim;
111 int i;
112 int ret;
113
114 cg_proto = tcp_prot.proto_cgroup(memcg);
115 if (!cg_proto)
116 return -EINVAL;
117
118 if (val > RESOURCE_MAX)
119 val = RESOURCE_MAX;
120
121 tcp = tcp_from_cgproto(cg_proto);
122
123 old_lim = res_counter_read_u64(&tcp->tcp_memory_allocated, RES_LIMIT);
124 ret = res_counter_set_limit(&tcp->tcp_memory_allocated, val);
125 if (ret)
126 return ret;
127
128 for (i = 0; i < 3; i++)
129 tcp->tcp_prot_mem[i] = min_t(long, val >> PAGE_SHIFT,
130 net->ipv4.sysctl_tcp_mem[i]);
131
132 if (val == RESOURCE_MAX && old_lim != RESOURCE_MAX)
133 jump_label_dec(&memcg_socket_limit_enabled);
134 else if (old_lim == RESOURCE_MAX && val != RESOURCE_MAX)
135 jump_label_inc(&memcg_socket_limit_enabled);
136
137 return 0;
138}
139
140static int tcp_cgroup_write(struct cgroup *cont, struct cftype *cft,
141 const char *buffer)
142{
143 struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
144 unsigned long long val;
145 int ret = 0;
146
147 switch (cft->private) {
148 case RES_LIMIT:
149 /* see memcontrol.c */
150 ret = res_counter_memparse_write_strategy(buffer, &val);
151 if (ret)
152 break;
153 ret = tcp_update_limit(memcg, val);
154 break;
155 default:
156 ret = -EINVAL;
157 break;
158 }
159 return ret;
160}
161
162static u64 tcp_read_stat(struct mem_cgroup *memcg, int type, u64 default_val)
163{
164 struct tcp_memcontrol *tcp;
165 struct cg_proto *cg_proto;
166
167 cg_proto = tcp_prot.proto_cgroup(memcg);
168 if (!cg_proto)
169 return default_val;
170
171 tcp = tcp_from_cgproto(cg_proto);
172 return res_counter_read_u64(&tcp->tcp_memory_allocated, type);
173}
174
Glauber Costa5a6dd342011-12-11 21:47:07 +0000175static u64 tcp_read_usage(struct mem_cgroup *memcg)
176{
177 struct tcp_memcontrol *tcp;
178 struct cg_proto *cg_proto;
179
180 cg_proto = tcp_prot.proto_cgroup(memcg);
181 if (!cg_proto)
182 return atomic_long_read(&tcp_memory_allocated) << PAGE_SHIFT;
183
184 tcp = tcp_from_cgproto(cg_proto);
185 return res_counter_read_u64(&tcp->tcp_memory_allocated, RES_USAGE);
186}
187
Glauber Costa3aaabe22011-12-11 21:47:06 +0000188static u64 tcp_cgroup_read(struct cgroup *cont, struct cftype *cft)
189{
190 struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
191 u64 val;
192
193 switch (cft->private) {
194 case RES_LIMIT:
195 val = tcp_read_stat(memcg, RES_LIMIT, RESOURCE_MAX);
196 break;
Glauber Costa5a6dd342011-12-11 21:47:07 +0000197 case RES_USAGE:
198 val = tcp_read_usage(memcg);
199 break;
Glauber Costa3aaabe22011-12-11 21:47:06 +0000200 default:
201 BUG();
202 }
203 return val;
204}
205
206unsigned long long tcp_max_memory(const struct mem_cgroup *memcg)
207{
208 struct tcp_memcontrol *tcp;
209 struct cg_proto *cg_proto;
210
211 cg_proto = tcp_prot.proto_cgroup((struct mem_cgroup *)memcg);
212 if (!cg_proto)
213 return 0;
214
215 tcp = tcp_from_cgproto(cg_proto);
216 return res_counter_read_u64(&tcp->tcp_memory_allocated, RES_LIMIT);
217}
218
219void tcp_prot_mem(struct mem_cgroup *memcg, long val, int idx)
220{
221 struct tcp_memcontrol *tcp;
222 struct cg_proto *cg_proto;
223
224 cg_proto = tcp_prot.proto_cgroup(memcg);
225 if (!cg_proto)
226 return;
227
228 tcp = tcp_from_cgproto(cg_proto);
229
230 tcp->tcp_prot_mem[idx] = val;
231}