diff options
Diffstat (limited to 'net/ipv4/tcp_memcontrol.c')
-rw-r--r-- | net/ipv4/tcp_memcontrol.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c new file mode 100644 index 000000000000..4a68d2c24556 --- /dev/null +++ b/net/ipv4/tcp_memcontrol.c | |||
@@ -0,0 +1,74 @@ | |||
1 | #include <net/tcp.h> | ||
2 | #include <net/tcp_memcontrol.h> | ||
3 | #include <net/sock.h> | ||
4 | #include <linux/memcontrol.h> | ||
5 | #include <linux/module.h> | ||
6 | |||
7 | static inline struct tcp_memcontrol *tcp_from_cgproto(struct cg_proto *cg_proto) | ||
8 | { | ||
9 | return container_of(cg_proto, struct tcp_memcontrol, cg_proto); | ||
10 | } | ||
11 | |||
12 | static void memcg_tcp_enter_memory_pressure(struct sock *sk) | ||
13 | { | ||
14 | if (!sk->sk_cgrp->memory_pressure) | ||
15 | *sk->sk_cgrp->memory_pressure = 1; | ||
16 | } | ||
17 | EXPORT_SYMBOL(memcg_tcp_enter_memory_pressure); | ||
18 | |||
19 | int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss) | ||
20 | { | ||
21 | /* | ||
22 | * The root cgroup does not use res_counters, but rather, | ||
23 | * rely on the data already collected by the network | ||
24 | * subsystem | ||
25 | */ | ||
26 | struct res_counter *res_parent = NULL; | ||
27 | struct cg_proto *cg_proto, *parent_cg; | ||
28 | struct tcp_memcontrol *tcp; | ||
29 | struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp); | ||
30 | struct mem_cgroup *parent = parent_mem_cgroup(memcg); | ||
31 | |||
32 | cg_proto = tcp_prot.proto_cgroup(memcg); | ||
33 | if (!cg_proto) | ||
34 | return 0; | ||
35 | |||
36 | tcp = tcp_from_cgproto(cg_proto); | ||
37 | |||
38 | tcp->tcp_prot_mem[0] = sysctl_tcp_mem[0]; | ||
39 | tcp->tcp_prot_mem[1] = sysctl_tcp_mem[1]; | ||
40 | tcp->tcp_prot_mem[2] = sysctl_tcp_mem[2]; | ||
41 | tcp->tcp_memory_pressure = 0; | ||
42 | |||
43 | parent_cg = tcp_prot.proto_cgroup(parent); | ||
44 | if (parent_cg) | ||
45 | res_parent = parent_cg->memory_allocated; | ||
46 | |||
47 | res_counter_init(&tcp->tcp_memory_allocated, res_parent); | ||
48 | percpu_counter_init(&tcp->tcp_sockets_allocated, 0); | ||
49 | |||
50 | cg_proto->enter_memory_pressure = memcg_tcp_enter_memory_pressure; | ||
51 | cg_proto->memory_pressure = &tcp->tcp_memory_pressure; | ||
52 | cg_proto->sysctl_mem = tcp->tcp_prot_mem; | ||
53 | cg_proto->memory_allocated = &tcp->tcp_memory_allocated; | ||
54 | cg_proto->sockets_allocated = &tcp->tcp_sockets_allocated; | ||
55 | cg_proto->memcg = memcg; | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | EXPORT_SYMBOL(tcp_init_cgroup); | ||
60 | |||
61 | void tcp_destroy_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss) | ||
62 | { | ||
63 | struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp); | ||
64 | struct cg_proto *cg_proto; | ||
65 | struct tcp_memcontrol *tcp; | ||
66 | |||
67 | cg_proto = tcp_prot.proto_cgroup(memcg); | ||
68 | if (!cg_proto) | ||
69 | return; | ||
70 | |||
71 | tcp = tcp_from_cgproto(cg_proto); | ||
72 | percpu_counter_destroy(&tcp->tcp_sockets_allocated); | ||
73 | } | ||
74 | EXPORT_SYMBOL(tcp_destroy_cgroup); | ||