Display current tcp failcnt in kmem cgroup
[linux-2.6-block.git] / net / ipv4 / tcp_memcontrol.c
CommitLineData
d1a4c0b3
GC
1#include <net/tcp.h>
2#include <net/tcp_memcontrol.h>
3#include <net/sock.h>
3dc43e3e
GC
4#include <net/ip.h>
5#include <linux/nsproxy.h>
d1a4c0b3
GC
6#include <linux/memcontrol.h>
7#include <linux/module.h>
8
3aaabe23
GC
9static 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);
ffea59e5 12static int tcp_cgroup_reset(struct cgroup *cont, unsigned int event);
3aaabe23
GC
13
14static struct cftype tcp_files[] = {
15 {
16 .name = "kmem.tcp.limit_in_bytes",
17 .write_string = tcp_cgroup_write,
18 .read_u64 = tcp_cgroup_read,
19 .private = RES_LIMIT,
20 },
5a6dd343
GC
21 {
22 .name = "kmem.tcp.usage_in_bytes",
23 .read_u64 = tcp_cgroup_read,
24 .private = RES_USAGE,
25 },
ffea59e5
GC
26 {
27 .name = "kmem.tcp.failcnt",
28 .private = RES_FAILCNT,
29 .trigger = tcp_cgroup_reset,
30 .read_u64 = tcp_cgroup_read,
31 },
3aaabe23
GC
32};
33
d1a4c0b3
GC
34static inline struct tcp_memcontrol *tcp_from_cgproto(struct cg_proto *cg_proto)
35{
36 return container_of(cg_proto, struct tcp_memcontrol, cg_proto);
37}
38
39static void memcg_tcp_enter_memory_pressure(struct sock *sk)
40{
41 if (!sk->sk_cgrp->memory_pressure)
42 *sk->sk_cgrp->memory_pressure = 1;
43}
44EXPORT_SYMBOL(memcg_tcp_enter_memory_pressure);
45
46int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss)
47{
48 /*
49 * The root cgroup does not use res_counters, but rather,
50 * rely on the data already collected by the network
51 * subsystem
52 */
53 struct res_counter *res_parent = NULL;
54 struct cg_proto *cg_proto, *parent_cg;
55 struct tcp_memcontrol *tcp;
56 struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
57 struct mem_cgroup *parent = parent_mem_cgroup(memcg);
3dc43e3e 58 struct net *net = current->nsproxy->net_ns;
d1a4c0b3
GC
59
60 cg_proto = tcp_prot.proto_cgroup(memcg);
61 if (!cg_proto)
3aaabe23 62 goto create_files;
d1a4c0b3
GC
63
64 tcp = tcp_from_cgproto(cg_proto);
65
3dc43e3e
GC
66 tcp->tcp_prot_mem[0] = net->ipv4.sysctl_tcp_mem[0];
67 tcp->tcp_prot_mem[1] = net->ipv4.sysctl_tcp_mem[1];
68 tcp->tcp_prot_mem[2] = net->ipv4.sysctl_tcp_mem[2];
d1a4c0b3
GC
69 tcp->tcp_memory_pressure = 0;
70
71 parent_cg = tcp_prot.proto_cgroup(parent);
72 if (parent_cg)
73 res_parent = parent_cg->memory_allocated;
74
75 res_counter_init(&tcp->tcp_memory_allocated, res_parent);
76 percpu_counter_init(&tcp->tcp_sockets_allocated, 0);
77
78 cg_proto->enter_memory_pressure = memcg_tcp_enter_memory_pressure;
79 cg_proto->memory_pressure = &tcp->tcp_memory_pressure;
80 cg_proto->sysctl_mem = tcp->tcp_prot_mem;
81 cg_proto->memory_allocated = &tcp->tcp_memory_allocated;
82 cg_proto->sockets_allocated = &tcp->tcp_sockets_allocated;
83 cg_proto->memcg = memcg;
84
3aaabe23
GC
85create_files:
86 return cgroup_add_files(cgrp, ss, tcp_files,
87 ARRAY_SIZE(tcp_files));
d1a4c0b3
GC
88}
89EXPORT_SYMBOL(tcp_init_cgroup);
90
91void tcp_destroy_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss)
92{
93 struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
94 struct cg_proto *cg_proto;
95 struct tcp_memcontrol *tcp;
3aaabe23 96 u64 val;
d1a4c0b3
GC
97
98 cg_proto = tcp_prot.proto_cgroup(memcg);
99 if (!cg_proto)
100 return;
101
102 tcp = tcp_from_cgproto(cg_proto);
103 percpu_counter_destroy(&tcp->tcp_sockets_allocated);
3aaabe23
GC
104
105 val = res_counter_read_u64(&tcp->tcp_memory_allocated, RES_USAGE);
106
107 if (val != RESOURCE_MAX)
108 jump_label_dec(&memcg_socket_limit_enabled);
d1a4c0b3
GC
109}
110EXPORT_SYMBOL(tcp_destroy_cgroup);
3aaabe23
GC
111
112static int tcp_update_limit(struct mem_cgroup *memcg, u64 val)
113{
114 struct net *net = current->nsproxy->net_ns;
115 struct tcp_memcontrol *tcp;
116 struct cg_proto *cg_proto;
117 u64 old_lim;
118 int i;
119 int ret;
120
121 cg_proto = tcp_prot.proto_cgroup(memcg);
122 if (!cg_proto)
123 return -EINVAL;
124
125 if (val > RESOURCE_MAX)
126 val = RESOURCE_MAX;
127
128 tcp = tcp_from_cgproto(cg_proto);
129
130 old_lim = res_counter_read_u64(&tcp->tcp_memory_allocated, RES_LIMIT);
131 ret = res_counter_set_limit(&tcp->tcp_memory_allocated, val);
132 if (ret)
133 return ret;
134
135 for (i = 0; i < 3; i++)
136 tcp->tcp_prot_mem[i] = min_t(long, val >> PAGE_SHIFT,
137 net->ipv4.sysctl_tcp_mem[i]);
138
139 if (val == RESOURCE_MAX && old_lim != RESOURCE_MAX)
140 jump_label_dec(&memcg_socket_limit_enabled);
141 else if (old_lim == RESOURCE_MAX && val != RESOURCE_MAX)
142 jump_label_inc(&memcg_socket_limit_enabled);
143
144 return 0;
145}
146
147static int tcp_cgroup_write(struct cgroup *cont, struct cftype *cft,
148 const char *buffer)
149{
150 struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
151 unsigned long long val;
152 int ret = 0;
153
154 switch (cft->private) {
155 case RES_LIMIT:
156 /* see memcontrol.c */
157 ret = res_counter_memparse_write_strategy(buffer, &val);
158 if (ret)
159 break;
160 ret = tcp_update_limit(memcg, val);
161 break;
162 default:
163 ret = -EINVAL;
164 break;
165 }
166 return ret;
167}
168
169static u64 tcp_read_stat(struct mem_cgroup *memcg, int type, u64 default_val)
170{
171 struct tcp_memcontrol *tcp;
172 struct cg_proto *cg_proto;
173
174 cg_proto = tcp_prot.proto_cgroup(memcg);
175 if (!cg_proto)
176 return default_val;
177
178 tcp = tcp_from_cgproto(cg_proto);
179 return res_counter_read_u64(&tcp->tcp_memory_allocated, type);
180}
181
5a6dd343
GC
182static u64 tcp_read_usage(struct mem_cgroup *memcg)
183{
184 struct tcp_memcontrol *tcp;
185 struct cg_proto *cg_proto;
186
187 cg_proto = tcp_prot.proto_cgroup(memcg);
188 if (!cg_proto)
189 return atomic_long_read(&tcp_memory_allocated) << PAGE_SHIFT;
190
191 tcp = tcp_from_cgproto(cg_proto);
192 return res_counter_read_u64(&tcp->tcp_memory_allocated, RES_USAGE);
193}
194
3aaabe23
GC
195static u64 tcp_cgroup_read(struct cgroup *cont, struct cftype *cft)
196{
197 struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
198 u64 val;
199
200 switch (cft->private) {
201 case RES_LIMIT:
202 val = tcp_read_stat(memcg, RES_LIMIT, RESOURCE_MAX);
203 break;
5a6dd343
GC
204 case RES_USAGE:
205 val = tcp_read_usage(memcg);
206 break;
ffea59e5
GC
207 case RES_FAILCNT:
208 val = tcp_read_stat(memcg, RES_FAILCNT, 0);
209 break;
3aaabe23
GC
210 default:
211 BUG();
212 }
213 return val;
214}
215
ffea59e5
GC
216static int tcp_cgroup_reset(struct cgroup *cont, unsigned int event)
217{
218 struct mem_cgroup *memcg;
219 struct tcp_memcontrol *tcp;
220 struct cg_proto *cg_proto;
221
222 memcg = mem_cgroup_from_cont(cont);
223 cg_proto = tcp_prot.proto_cgroup(memcg);
224 if (!cg_proto)
225 return 0;
226 tcp = tcp_from_cgproto(cg_proto);
227
228 switch (event) {
229 case RES_FAILCNT:
230 res_counter_reset_failcnt(&tcp->tcp_memory_allocated);
231 break;
232 }
233
234 return 0;
235}
236
3aaabe23
GC
237unsigned long long tcp_max_memory(const struct mem_cgroup *memcg)
238{
239 struct tcp_memcontrol *tcp;
240 struct cg_proto *cg_proto;
241
242 cg_proto = tcp_prot.proto_cgroup((struct mem_cgroup *)memcg);
243 if (!cg_proto)
244 return 0;
245
246 tcp = tcp_from_cgproto(cg_proto);
247 return res_counter_read_u64(&tcp->tcp_memory_allocated, RES_LIMIT);
248}
249
250void tcp_prot_mem(struct mem_cgroup *memcg, long val, int idx)
251{
252 struct tcp_memcontrol *tcp;
253 struct cg_proto *cg_proto;
254
255 cg_proto = tcp_prot.proto_cgroup(memcg);
256 if (!cg_proto)
257 return;
258
259 tcp = tcp_from_cgproto(cg_proto);
260
261 tcp->tcp_prot_mem[idx] = val;
262}