Commit 296c81d89f4f14269f7346f81442910158c0a83a

Authored by Balbir Singh
Committed by Linus Torvalds
1 parent a6df63615b

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();
... ... @@ -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 },