diff options
Diffstat (limited to 'net/ipv4/tcp_memcontrol.c')
-rw-r--r-- | net/ipv4/tcp_memcontrol.c | 87 |
1 files changed, 44 insertions, 43 deletions
diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c index 1d191357bf88..272327134a1b 100644 --- a/net/ipv4/tcp_memcontrol.c +++ b/net/ipv4/tcp_memcontrol.c | |||
@@ -9,13 +9,13 @@ | |||
9 | int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss) | 9 | int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss) |
10 | { | 10 | { |
11 | /* | 11 | /* |
12 | * The root cgroup does not use res_counters, but rather, | 12 | * The root cgroup does not use page_counters, but rather, |
13 | * rely on the data already collected by the network | 13 | * rely on the data already collected by the network |
14 | * subsystem | 14 | * subsystem |
15 | */ | 15 | */ |
16 | struct res_counter *res_parent = NULL; | ||
17 | struct cg_proto *cg_proto, *parent_cg; | ||
18 | struct mem_cgroup *parent = parent_mem_cgroup(memcg); | 16 | struct mem_cgroup *parent = parent_mem_cgroup(memcg); |
17 | struct page_counter *counter_parent = NULL; | ||
18 | struct cg_proto *cg_proto, *parent_cg; | ||
19 | 19 | ||
20 | cg_proto = tcp_prot.proto_cgroup(memcg); | 20 | cg_proto = tcp_prot.proto_cgroup(memcg); |
21 | if (!cg_proto) | 21 | if (!cg_proto) |
@@ -29,9 +29,9 @@ int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss) | |||
29 | 29 | ||
30 | parent_cg = tcp_prot.proto_cgroup(parent); | 30 | parent_cg = tcp_prot.proto_cgroup(parent); |
31 | if (parent_cg) | 31 | if (parent_cg) |
32 | res_parent = &parent_cg->memory_allocated; | 32 | counter_parent = &parent_cg->memory_allocated; |
33 | 33 | ||
34 | res_counter_init(&cg_proto->memory_allocated, res_parent); | 34 | page_counter_init(&cg_proto->memory_allocated, counter_parent); |
35 | percpu_counter_init(&cg_proto->sockets_allocated, 0, GFP_KERNEL); | 35 | percpu_counter_init(&cg_proto->sockets_allocated, 0, GFP_KERNEL); |
36 | 36 | ||
37 | return 0; | 37 | return 0; |
@@ -50,7 +50,7 @@ void tcp_destroy_cgroup(struct mem_cgroup *memcg) | |||
50 | } | 50 | } |
51 | EXPORT_SYMBOL(tcp_destroy_cgroup); | 51 | EXPORT_SYMBOL(tcp_destroy_cgroup); |
52 | 52 | ||
53 | static int tcp_update_limit(struct mem_cgroup *memcg, u64 val) | 53 | static int tcp_update_limit(struct mem_cgroup *memcg, unsigned long nr_pages) |
54 | { | 54 | { |
55 | struct cg_proto *cg_proto; | 55 | struct cg_proto *cg_proto; |
56 | int i; | 56 | int i; |
@@ -60,20 +60,17 @@ static int tcp_update_limit(struct mem_cgroup *memcg, u64 val) | |||
60 | if (!cg_proto) | 60 | if (!cg_proto) |
61 | return -EINVAL; | 61 | return -EINVAL; |
62 | 62 | ||
63 | if (val > RES_COUNTER_MAX) | 63 | ret = page_counter_limit(&cg_proto->memory_allocated, nr_pages); |
64 | val = RES_COUNTER_MAX; | ||
65 | |||
66 | ret = res_counter_set_limit(&cg_proto->memory_allocated, val); | ||
67 | if (ret) | 64 | if (ret) |
68 | return ret; | 65 | return ret; |
69 | 66 | ||
70 | for (i = 0; i < 3; i++) | 67 | for (i = 0; i < 3; i++) |
71 | cg_proto->sysctl_mem[i] = min_t(long, val >> PAGE_SHIFT, | 68 | cg_proto->sysctl_mem[i] = min_t(long, nr_pages, |
72 | sysctl_tcp_mem[i]); | 69 | sysctl_tcp_mem[i]); |
73 | 70 | ||
74 | if (val == RES_COUNTER_MAX) | 71 | if (nr_pages == PAGE_COUNTER_MAX) |
75 | clear_bit(MEMCG_SOCK_ACTIVE, &cg_proto->flags); | 72 | clear_bit(MEMCG_SOCK_ACTIVE, &cg_proto->flags); |
76 | else if (val != RES_COUNTER_MAX) { | 73 | else { |
77 | /* | 74 | /* |
78 | * The active bit needs to be written after the static_key | 75 | * The active bit needs to be written after the static_key |
79 | * update. This is what guarantees that the socket activation | 76 | * update. This is what guarantees that the socket activation |
@@ -102,11 +99,20 @@ static int tcp_update_limit(struct mem_cgroup *memcg, u64 val) | |||
102 | return 0; | 99 | return 0; |
103 | } | 100 | } |
104 | 101 | ||
102 | enum { | ||
103 | RES_USAGE, | ||
104 | RES_LIMIT, | ||
105 | RES_MAX_USAGE, | ||
106 | RES_FAILCNT, | ||
107 | }; | ||
108 | |||
109 | static DEFINE_MUTEX(tcp_limit_mutex); | ||
110 | |||
105 | static ssize_t tcp_cgroup_write(struct kernfs_open_file *of, | 111 | static ssize_t tcp_cgroup_write(struct kernfs_open_file *of, |
106 | char *buf, size_t nbytes, loff_t off) | 112 | char *buf, size_t nbytes, loff_t off) |
107 | { | 113 | { |
108 | struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of)); | 114 | struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of)); |
109 | unsigned long long val; | 115 | unsigned long nr_pages; |
110 | int ret = 0; | 116 | int ret = 0; |
111 | 117 | ||
112 | buf = strstrip(buf); | 118 | buf = strstrip(buf); |
@@ -114,10 +120,12 @@ static ssize_t tcp_cgroup_write(struct kernfs_open_file *of, | |||
114 | switch (of_cft(of)->private) { | 120 | switch (of_cft(of)->private) { |
115 | case RES_LIMIT: | 121 | case RES_LIMIT: |
116 | /* see memcontrol.c */ | 122 | /* see memcontrol.c */ |
117 | ret = res_counter_memparse_write_strategy(buf, &val); | 123 | ret = page_counter_memparse(buf, &nr_pages); |
118 | if (ret) | 124 | if (ret) |
119 | break; | 125 | break; |
120 | ret = tcp_update_limit(memcg, val); | 126 | mutex_lock(&tcp_limit_mutex); |
127 | ret = tcp_update_limit(memcg, nr_pages); | ||
128 | mutex_unlock(&tcp_limit_mutex); | ||
121 | break; | 129 | break; |
122 | default: | 130 | default: |
123 | ret = -EINVAL; | 131 | ret = -EINVAL; |
@@ -126,43 +134,36 @@ static ssize_t tcp_cgroup_write(struct kernfs_open_file *of, | |||
126 | return ret ?: nbytes; | 134 | return ret ?: nbytes; |
127 | } | 135 | } |
128 | 136 | ||
129 | static u64 tcp_read_stat(struct mem_cgroup *memcg, int type, u64 default_val) | ||
130 | { | ||
131 | struct cg_proto *cg_proto; | ||
132 | |||
133 | cg_proto = tcp_prot.proto_cgroup(memcg); | ||
134 | if (!cg_proto) | ||
135 | return default_val; | ||
136 | |||
137 | return res_counter_read_u64(&cg_proto->memory_allocated, type); | ||
138 | } | ||
139 | |||
140 | static u64 tcp_read_usage(struct mem_cgroup *memcg) | ||
141 | { | ||
142 | struct cg_proto *cg_proto; | ||
143 | |||
144 | cg_proto = tcp_prot.proto_cgroup(memcg); | ||
145 | if (!cg_proto) | ||
146 | return atomic_long_read(&tcp_memory_allocated) << PAGE_SHIFT; | ||
147 | |||
148 | return res_counter_read_u64(&cg_proto->memory_allocated, RES_USAGE); | ||
149 | } | ||
150 | |||
151 | static u64 tcp_cgroup_read(struct cgroup_subsys_state *css, struct cftype *cft) | 137 | static u64 tcp_cgroup_read(struct cgroup_subsys_state *css, struct cftype *cft) |
152 | { | 138 | { |
153 | struct mem_cgroup *memcg = mem_cgroup_from_css(css); | 139 | struct mem_cgroup *memcg = mem_cgroup_from_css(css); |
140 | struct cg_proto *cg_proto = tcp_prot.proto_cgroup(memcg); | ||
154 | u64 val; | 141 | u64 val; |
155 | 142 | ||
156 | switch (cft->private) { | 143 | switch (cft->private) { |
157 | case RES_LIMIT: | 144 | case RES_LIMIT: |
158 | val = tcp_read_stat(memcg, RES_LIMIT, RES_COUNTER_MAX); | 145 | if (!cg_proto) |
146 | return PAGE_COUNTER_MAX; | ||
147 | val = cg_proto->memory_allocated.limit; | ||
148 | val *= PAGE_SIZE; | ||
159 | break; | 149 | break; |
160 | case RES_USAGE: | 150 | case RES_USAGE: |
161 | val = tcp_read_usage(memcg); | 151 | if (!cg_proto) |
152 | val = atomic_long_read(&tcp_memory_allocated); | ||
153 | else | ||
154 | val = page_counter_read(&cg_proto->memory_allocated); | ||
155 | val *= PAGE_SIZE; | ||
162 | break; | 156 | break; |
163 | case RES_FAILCNT: | 157 | case RES_FAILCNT: |
158 | if (!cg_proto) | ||
159 | return 0; | ||
160 | val = cg_proto->memory_allocated.failcnt; | ||
161 | break; | ||
164 | case RES_MAX_USAGE: | 162 | case RES_MAX_USAGE: |
165 | val = tcp_read_stat(memcg, cft->private, 0); | 163 | if (!cg_proto) |
164 | return 0; | ||
165 | val = cg_proto->memory_allocated.watermark; | ||
166 | val *= PAGE_SIZE; | ||
166 | break; | 167 | break; |
167 | default: | 168 | default: |
168 | BUG(); | 169 | BUG(); |
@@ -183,10 +184,10 @@ static ssize_t tcp_cgroup_reset(struct kernfs_open_file *of, | |||
183 | 184 | ||
184 | switch (of_cft(of)->private) { | 185 | switch (of_cft(of)->private) { |
185 | case RES_MAX_USAGE: | 186 | case RES_MAX_USAGE: |
186 | res_counter_reset_max(&cg_proto->memory_allocated); | 187 | page_counter_reset_watermark(&cg_proto->memory_allocated); |
187 | break; | 188 | break; |
188 | case RES_FAILCNT: | 189 | case RES_FAILCNT: |
189 | res_counter_reset_failcnt(&cg_proto->memory_allocated); | 190 | cg_proto->memory_allocated.failcnt = 0; |
190 | break; | 191 | break; |
191 | } | 192 | } |
192 | 193 | ||