]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - net/ipv4/tcp_memcontrol.c
18bc7f745e9cadd8dde7e53ccc1fe2102fc15f8b
[karo-tx-linux.git] / net / ipv4 / tcp_memcontrol.c
1 #include <net/tcp.h>
2 #include <net/tcp_memcontrol.h>
3 #include <net/sock.h>
4 #include <net/ip.h>
5 #include <linux/nsproxy.h>
6 #include <linux/memcontrol.h>
7 #include <linux/module.h>
8
9 int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
10 {
11         struct mem_cgroup *parent = parent_mem_cgroup(memcg);
12         struct page_counter *counter_parent = NULL;
13         /*
14          * The root cgroup does not use page_counters, but rather,
15          * rely on the data already collected by the network
16          * subsystem
17          */
18         if (memcg == root_mem_cgroup)
19                 return 0;
20
21         memcg->tcp_mem.memory_pressure = 0;
22
23         if (parent)
24                 counter_parent = &parent->tcp_mem.memory_allocated;
25
26         page_counter_init(&memcg->tcp_mem.memory_allocated, counter_parent);
27
28         return 0;
29 }
30
31 void tcp_destroy_cgroup(struct mem_cgroup *memcg)
32 {
33         if (memcg == root_mem_cgroup)
34                 return;
35
36         if (memcg->tcp_mem.active)
37                 static_branch_dec(&memcg_sockets_enabled_key);
38 }
39
40 static int tcp_update_limit(struct mem_cgroup *memcg, unsigned long nr_pages)
41 {
42         int ret;
43
44         if (memcg == root_mem_cgroup)
45                 return -EINVAL;
46
47         ret = page_counter_limit(&memcg->tcp_mem.memory_allocated, nr_pages);
48         if (ret)
49                 return ret;
50
51         if (!memcg->tcp_mem.active) {
52                 /*
53                  * The active flag needs to be written after the static_key
54                  * update. This is what guarantees that the socket activation
55                  * function is the last one to run. See sock_update_memcg() for
56                  * details, and note that we don't mark any socket as belonging
57                  * to this memcg until that flag is up.
58                  *
59                  * We need to do this, because static_keys will span multiple
60                  * sites, but we can't control their order. If we mark a socket
61                  * as accounted, but the accounting functions are not patched in
62                  * yet, we'll lose accounting.
63                  *
64                  * We never race with the readers in sock_update_memcg(),
65                  * because when this value change, the code to process it is not
66                  * patched in yet.
67                  */
68                 static_branch_inc(&memcg_sockets_enabled_key);
69                 memcg->tcp_mem.active = true;
70         }
71
72         return 0;
73 }
74
75 enum {
76         RES_USAGE,
77         RES_LIMIT,
78         RES_MAX_USAGE,
79         RES_FAILCNT,
80 };
81
82 static DEFINE_MUTEX(tcp_limit_mutex);
83
84 static ssize_t tcp_cgroup_write(struct kernfs_open_file *of,
85                                 char *buf, size_t nbytes, loff_t off)
86 {
87         struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
88         unsigned long nr_pages;
89         int ret = 0;
90
91         buf = strstrip(buf);
92
93         switch (of_cft(of)->private) {
94         case RES_LIMIT:
95                 /* see memcontrol.c */
96                 ret = page_counter_memparse(buf, "-1", &nr_pages);
97                 if (ret)
98                         break;
99                 mutex_lock(&tcp_limit_mutex);
100                 ret = tcp_update_limit(memcg, nr_pages);
101                 mutex_unlock(&tcp_limit_mutex);
102                 break;
103         default:
104                 ret = -EINVAL;
105                 break;
106         }
107         return ret ?: nbytes;
108 }
109
110 static u64 tcp_cgroup_read(struct cgroup_subsys_state *css, struct cftype *cft)
111 {
112         struct mem_cgroup *memcg = mem_cgroup_from_css(css);
113         u64 val;
114
115         switch (cft->private) {
116         case RES_LIMIT:
117                 if (memcg == root_mem_cgroup)
118                         val = PAGE_COUNTER_MAX;
119                 else
120                         val = memcg->tcp_mem.memory_allocated.limit;
121                 val *= PAGE_SIZE;
122                 break;
123         case RES_USAGE:
124                 if (memcg == root_mem_cgroup)
125                         val = atomic_long_read(&tcp_memory_allocated);
126                 else
127                         val = page_counter_read(&memcg->tcp_mem.memory_allocated);
128                 val *= PAGE_SIZE;
129                 break;
130         case RES_FAILCNT:
131                 if (memcg == root_mem_cgroup)
132                         return 0;
133                 val = memcg->tcp_mem.memory_allocated.failcnt;
134                 break;
135         case RES_MAX_USAGE:
136                 if (memcg == root_mem_cgroup)
137                         return 0;
138                 val = memcg->tcp_mem.memory_allocated.watermark;
139                 val *= PAGE_SIZE;
140                 break;
141         default:
142                 BUG();
143         }
144         return val;
145 }
146
147 static ssize_t tcp_cgroup_reset(struct kernfs_open_file *of,
148                                 char *buf, size_t nbytes, loff_t off)
149 {
150         struct mem_cgroup *memcg;
151
152         memcg = mem_cgroup_from_css(of_css(of));
153         if (memcg == root_mem_cgroup)
154                 return nbytes;
155
156         switch (of_cft(of)->private) {
157         case RES_MAX_USAGE:
158                 page_counter_reset_watermark(&memcg->tcp_mem.memory_allocated);
159                 break;
160         case RES_FAILCNT:
161                 memcg->tcp_mem.memory_allocated.failcnt = 0;
162                 break;
163         }
164
165         return nbytes;
166 }
167
168 static struct cftype tcp_files[] = {
169         {
170                 .name = "kmem.tcp.limit_in_bytes",
171                 .write = tcp_cgroup_write,
172                 .read_u64 = tcp_cgroup_read,
173                 .private = RES_LIMIT,
174         },
175         {
176                 .name = "kmem.tcp.usage_in_bytes",
177                 .read_u64 = tcp_cgroup_read,
178                 .private = RES_USAGE,
179         },
180         {
181                 .name = "kmem.tcp.failcnt",
182                 .private = RES_FAILCNT,
183                 .write = tcp_cgroup_reset,
184                 .read_u64 = tcp_cgroup_read,
185         },
186         {
187                 .name = "kmem.tcp.max_usage_in_bytes",
188                 .private = RES_MAX_USAGE,
189                 .write = tcp_cgroup_reset,
190                 .read_u64 = tcp_cgroup_read,
191         },
192         { }     /* terminate */
193 };
194
195 static int __init tcp_memcontrol_init(void)
196 {
197         WARN_ON(cgroup_add_legacy_cftypes(&memory_cgrp_subsys, tcp_files));
198         return 0;
199 }
200 __initcall(tcp_memcontrol_init);