Commit 296c81d89f4f14269f7346f81442910158c0a83a
Committed by
Linus Torvalds
1 parent
a6df63615b
Exists in
master
and in
7 other branches
memory controller: soft limit interface
Add an interface to allow get/set of soft limits. Soft limits for memory plus swap controller (memsw) is currently not supported. Resource counters have been enhanced to support soft limits and new type RES_SOFT_LIMIT has been added. Unlike hard limits, soft limits can be directly set and do not need any reclaim or checks before setting them to a newer value. Kamezawa-San raised a question as to whether soft limit should belong to res_counter. Since all resources understand the basic concepts of hard and soft limits, it is justified to add soft limits here. Soft limits are a generic resource usage feature, even file system quotas support soft limits. Signed-off-by: Balbir Singh <balbir@linux.vnet.ibm.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 3 changed files with 81 additions and 0 deletions Side-by-side Diff
include/linux/res_counter.h
... | ... | @@ -35,6 +35,10 @@ |
35 | 35 | */ |
36 | 36 | unsigned long long limit; |
37 | 37 | /* |
38 | + * the limit that usage can be exceed | |
39 | + */ | |
40 | + unsigned long long soft_limit; | |
41 | + /* | |
38 | 42 | * the number of unsuccessful attempts to consume the resource |
39 | 43 | */ |
40 | 44 | unsigned long long failcnt; |
... | ... | @@ -87,6 +91,7 @@ |
87 | 91 | RES_MAX_USAGE, |
88 | 92 | RES_LIMIT, |
89 | 93 | RES_FAILCNT, |
94 | + RES_SOFT_LIMIT, | |
90 | 95 | }; |
91 | 96 | |
92 | 97 | /* |
... | ... | @@ -132,6 +137,36 @@ |
132 | 137 | return false; |
133 | 138 | } |
134 | 139 | |
140 | +static inline bool res_counter_soft_limit_check_locked(struct res_counter *cnt) | |
141 | +{ | |
142 | + if (cnt->usage < cnt->soft_limit) | |
143 | + return true; | |
144 | + | |
145 | + return false; | |
146 | +} | |
147 | + | |
148 | +/** | |
149 | + * Get the difference between the usage and the soft limit | |
150 | + * @cnt: The counter | |
151 | + * | |
152 | + * Returns 0 if usage is less than or equal to soft limit | |
153 | + * The difference between usage and soft limit, otherwise. | |
154 | + */ | |
155 | +static inline unsigned long long | |
156 | +res_counter_soft_limit_excess(struct res_counter *cnt) | |
157 | +{ | |
158 | + unsigned long long excess; | |
159 | + unsigned long flags; | |
160 | + | |
161 | + spin_lock_irqsave(&cnt->lock, flags); | |
162 | + if (cnt->usage <= cnt->soft_limit) | |
163 | + excess = 0; | |
164 | + else | |
165 | + excess = cnt->usage - cnt->soft_limit; | |
166 | + spin_unlock_irqrestore(&cnt->lock, flags); | |
167 | + return excess; | |
168 | +} | |
169 | + | |
135 | 170 | /* |
136 | 171 | * Helper function to detect if the cgroup is within it's limit or |
137 | 172 | * not. It's currently called from cgroup_rss_prepare() |
... | ... | @@ -147,6 +182,17 @@ |
147 | 182 | return ret; |
148 | 183 | } |
149 | 184 | |
185 | +static inline bool res_counter_check_under_soft_limit(struct res_counter *cnt) | |
186 | +{ | |
187 | + bool ret; | |
188 | + unsigned long flags; | |
189 | + | |
190 | + spin_lock_irqsave(&cnt->lock, flags); | |
191 | + ret = res_counter_soft_limit_check_locked(cnt); | |
192 | + spin_unlock_irqrestore(&cnt->lock, flags); | |
193 | + return ret; | |
194 | +} | |
195 | + | |
150 | 196 | static inline void res_counter_reset_max(struct res_counter *cnt) |
151 | 197 | { |
152 | 198 | unsigned long flags; |
... | ... | @@ -178,6 +224,18 @@ |
178 | 224 | } |
179 | 225 | spin_unlock_irqrestore(&cnt->lock, flags); |
180 | 226 | return ret; |
227 | +} | |
228 | + | |
229 | +static inline int | |
230 | +res_counter_set_soft_limit(struct res_counter *cnt, | |
231 | + unsigned long long soft_limit) | |
232 | +{ | |
233 | + unsigned long flags; | |
234 | + | |
235 | + spin_lock_irqsave(&cnt->lock, flags); | |
236 | + cnt->soft_limit = soft_limit; | |
237 | + spin_unlock_irqrestore(&cnt->lock, flags); | |
238 | + return 0; | |
181 | 239 | } |
182 | 240 | |
183 | 241 | #endif |
kernel/res_counter.c
... | ... | @@ -19,6 +19,7 @@ |
19 | 19 | { |
20 | 20 | spin_lock_init(&counter->lock); |
21 | 21 | counter->limit = RESOURCE_MAX; |
22 | + counter->soft_limit = RESOURCE_MAX; | |
22 | 23 | counter->parent = parent; |
23 | 24 | } |
24 | 25 | |
... | ... | @@ -101,6 +102,8 @@ |
101 | 102 | return &counter->limit; |
102 | 103 | case RES_FAILCNT: |
103 | 104 | return &counter->failcnt; |
105 | + case RES_SOFT_LIMIT: | |
106 | + return &counter->soft_limit; | |
104 | 107 | }; |
105 | 108 | |
106 | 109 | BUG(); |
mm/memcontrol.c
... | ... | @@ -2123,6 +2123,20 @@ |
2123 | 2123 | else |
2124 | 2124 | ret = mem_cgroup_resize_memsw_limit(memcg, val); |
2125 | 2125 | break; |
2126 | + case RES_SOFT_LIMIT: | |
2127 | + ret = res_counter_memparse_write_strategy(buffer, &val); | |
2128 | + if (ret) | |
2129 | + break; | |
2130 | + /* | |
2131 | + * For memsw, soft limits are hard to implement in terms | |
2132 | + * of semantics, for now, we support soft limits for | |
2133 | + * control without swap | |
2134 | + */ | |
2135 | + if (type == _MEM) | |
2136 | + ret = res_counter_set_soft_limit(&memcg->res, val); | |
2137 | + else | |
2138 | + ret = -EINVAL; | |
2139 | + break; | |
2126 | 2140 | default: |
2127 | 2141 | ret = -EINVAL; /* should be BUG() ? */ |
2128 | 2142 | break; |
... | ... | @@ -2372,6 +2386,12 @@ |
2372 | 2386 | { |
2373 | 2387 | .name = "limit_in_bytes", |
2374 | 2388 | .private = MEMFILE_PRIVATE(_MEM, RES_LIMIT), |
2389 | + .write_string = mem_cgroup_write, | |
2390 | + .read_u64 = mem_cgroup_read, | |
2391 | + }, | |
2392 | + { | |
2393 | + .name = "soft_limit_in_bytes", | |
2394 | + .private = MEMFILE_PRIVATE(_MEM, RES_SOFT_LIMIT), | |
2375 | 2395 | .write_string = mem_cgroup_write, |
2376 | 2396 | .read_u64 = mem_cgroup_read, |
2377 | 2397 | }, |