aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Weiner <hannes@cmpxchg.org>2011-03-23 19:42:21 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-23 22:46:23 -0400
commit9d11ea9f163a14920487bdda77461e64d600fd48 (patch)
tree9435e30836ee97f3e8c235451bc944cdc8a345c4
parentb7c6167848fa36e32f1874b95c1edc02881cd040 (diff)
memcg: simplify the way memory limits are checked
Since transparent huge pages, checking whether memory cgroups are below their limits is no longer enough, but the actual amount of chargeable space is important. To not have more than one limit-checking interface, replace memory_cgroup_check_under_limit() and memory_cgroup_check_margin() with a single memory_cgroup_margin() that returns the chargeable space and leaves the comparison to the callsite. Soft limits are now checked the other way round, by using the already existing function that returns the amount by which soft limits are exceeded: res_counter_soft_limit_excess(). Also remove all the corresponding functions on the res_counter side that are now no longer used. Signed-off-by: Johannes Weiner <hannes@cmpxchg.org> Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Acked-by: Balbir Singh <balbir@linux.vnet.ibm.com> Cc: Minchan Kim <minchan.kim@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/res_counter.h72
-rw-r--r--mm/memcontrol.c49
2 files changed, 31 insertions, 90 deletions
diff --git a/include/linux/res_counter.h b/include/linux/res_counter.h
index bf1f01bc013f..c9d625ca659e 100644
--- a/include/linux/res_counter.h
+++ b/include/linux/res_counter.h
@@ -129,20 +129,22 @@ int __must_check res_counter_charge(struct res_counter *counter,
129void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val); 129void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val);
130void res_counter_uncharge(struct res_counter *counter, unsigned long val); 130void res_counter_uncharge(struct res_counter *counter, unsigned long val);
131 131
132static inline bool res_counter_limit_check_locked(struct res_counter *cnt) 132/**
133{ 133 * res_counter_margin - calculate chargeable space of a counter
134 if (cnt->usage < cnt->limit) 134 * @cnt: the counter
135 return true; 135 *
136 136 * Returns the difference between the hard limit and the current usage
137 return false; 137 * of resource counter @cnt.
138} 138 */
139 139static inline unsigned long long res_counter_margin(struct res_counter *cnt)
140static inline bool res_counter_soft_limit_check_locked(struct res_counter *cnt)
141{ 140{
142 if (cnt->usage <= cnt->soft_limit) 141 unsigned long long margin;
143 return true; 142 unsigned long flags;
144 143
145 return false; 144 spin_lock_irqsave(&cnt->lock, flags);
145 margin = cnt->limit - cnt->usage;
146 spin_unlock_irqrestore(&cnt->lock, flags);
147 return margin;
146} 148}
147 149
148/** 150/**
@@ -167,52 +169,6 @@ res_counter_soft_limit_excess(struct res_counter *cnt)
167 return excess; 169 return excess;
168} 170}
169 171
170/*
171 * Helper function to detect if the cgroup is within it's limit or
172 * not. It's currently called from cgroup_rss_prepare()
173 */
174static inline bool res_counter_check_under_limit(struct res_counter *cnt)
175{
176 bool ret;
177 unsigned long flags;
178
179 spin_lock_irqsave(&cnt->lock, flags);
180 ret = res_counter_limit_check_locked(cnt);
181 spin_unlock_irqrestore(&cnt->lock, flags);
182 return ret;
183}
184
185/**
186 * res_counter_check_margin - check if the counter allows charging
187 * @cnt: the resource counter to check
188 * @bytes: the number of bytes to check the remaining space against
189 *
190 * Returns a boolean value on whether the counter can be charged
191 * @bytes or whether this would exceed the limit.
192 */
193static inline bool res_counter_check_margin(struct res_counter *cnt,
194 unsigned long bytes)
195{
196 bool ret;
197 unsigned long flags;
198
199 spin_lock_irqsave(&cnt->lock, flags);
200 ret = cnt->limit - cnt->usage >= bytes;
201 spin_unlock_irqrestore(&cnt->lock, flags);
202 return ret;
203}
204
205static inline bool res_counter_check_within_soft_limit(struct res_counter *cnt)
206{
207 bool ret;
208 unsigned long flags;
209
210 spin_lock_irqsave(&cnt->lock, flags);
211 ret = res_counter_soft_limit_check_locked(cnt);
212 spin_unlock_irqrestore(&cnt->lock, flags);
213 return ret;
214}
215
216static inline void res_counter_reset_max(struct res_counter *cnt) 172static inline void res_counter_reset_max(struct res_counter *cnt)
217{ 173{
218 unsigned long flags; 174 unsigned long flags;
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 13de53fe0108..62bbb48980e5 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -504,11 +504,6 @@ static void mem_cgroup_remove_from_trees(struct mem_cgroup *mem)
504 } 504 }
505} 505}
506 506
507static inline unsigned long mem_cgroup_get_excess(struct mem_cgroup *mem)
508{
509 return res_counter_soft_limit_excess(&mem->res) >> PAGE_SHIFT;
510}
511
512static struct mem_cgroup_per_zone * 507static struct mem_cgroup_per_zone *
513__mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_zone *mctz) 508__mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_zone *mctz)
514{ 509{
@@ -1127,33 +1122,21 @@ unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
1127#define mem_cgroup_from_res_counter(counter, member) \ 1122#define mem_cgroup_from_res_counter(counter, member) \
1128 container_of(counter, struct mem_cgroup, member) 1123 container_of(counter, struct mem_cgroup, member)
1129 1124
1130static bool mem_cgroup_check_under_limit(struct mem_cgroup *mem)
1131{
1132 if (do_swap_account) {
1133 if (res_counter_check_under_limit(&mem->res) &&
1134 res_counter_check_under_limit(&mem->memsw))
1135 return true;
1136 } else
1137 if (res_counter_check_under_limit(&mem->res))
1138 return true;
1139 return false;
1140}
1141
1142/** 1125/**
1143 * mem_cgroup_check_margin - check if the memory cgroup allows charging 1126 * mem_cgroup_margin - calculate chargeable space of a memory cgroup
1144 * @mem: memory cgroup to check 1127 * @mem: the memory cgroup
1145 * @bytes: the number of bytes the caller intends to charge
1146 * 1128 *
1147 * Returns a boolean value on whether @mem can be charged @bytes or 1129 * Returns the maximum amount of memory @mem can be charged with, in
1148 * whether this would exceed the limit. 1130 * bytes.
1149 */ 1131 */
1150static bool mem_cgroup_check_margin(struct mem_cgroup *mem, unsigned long bytes) 1132static unsigned long long mem_cgroup_margin(struct mem_cgroup *mem)
1151{ 1133{
1152 if (!res_counter_check_margin(&mem->res, bytes)) 1134 unsigned long long margin;
1153 return false; 1135
1154 if (do_swap_account && !res_counter_check_margin(&mem->memsw, bytes)) 1136 margin = res_counter_margin(&mem->res);
1155 return false; 1137 if (do_swap_account)
1156 return true; 1138 margin = min(margin, res_counter_margin(&mem->memsw));
1139 return margin;
1157} 1140}
1158 1141
1159static unsigned int get_swappiness(struct mem_cgroup *memcg) 1142static unsigned int get_swappiness(struct mem_cgroup *memcg)
@@ -1420,7 +1403,9 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
1420 bool noswap = reclaim_options & MEM_CGROUP_RECLAIM_NOSWAP; 1403 bool noswap = reclaim_options & MEM_CGROUP_RECLAIM_NOSWAP;
1421 bool shrink = reclaim_options & MEM_CGROUP_RECLAIM_SHRINK; 1404 bool shrink = reclaim_options & MEM_CGROUP_RECLAIM_SHRINK;
1422 bool check_soft = reclaim_options & MEM_CGROUP_RECLAIM_SOFT; 1405 bool check_soft = reclaim_options & MEM_CGROUP_RECLAIM_SOFT;
1423 unsigned long excess = mem_cgroup_get_excess(root_mem); 1406 unsigned long excess;
1407
1408 excess = res_counter_soft_limit_excess(&root_mem->res) >> PAGE_SHIFT;
1424 1409
1425 /* If memsw_is_minimum==1, swap-out is of-no-use. */ 1410 /* If memsw_is_minimum==1, swap-out is of-no-use. */
1426 if (root_mem->memsw_is_minimum) 1411 if (root_mem->memsw_is_minimum)
@@ -1477,9 +1462,9 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
1477 return ret; 1462 return ret;
1478 total += ret; 1463 total += ret;
1479 if (check_soft) { 1464 if (check_soft) {
1480 if (res_counter_check_within_soft_limit(&root_mem->res)) 1465 if (!res_counter_soft_limit_excess(&root_mem->res))
1481 return total; 1466 return total;
1482 } else if (mem_cgroup_check_under_limit(root_mem)) 1467 } else if (mem_cgroup_margin(root_mem))
1483 return 1 + total; 1468 return 1 + total;
1484 } 1469 }
1485 return total; 1470 return total;
@@ -1898,7 +1883,7 @@ static int __mem_cgroup_do_charge(struct mem_cgroup *mem, gfp_t gfp_mask,
1898 1883
1899 ret = mem_cgroup_hierarchical_reclaim(mem_over_limit, NULL, 1884 ret = mem_cgroup_hierarchical_reclaim(mem_over_limit, NULL,
1900 gfp_mask, flags); 1885 gfp_mask, flags);
1901 if (mem_cgroup_check_margin(mem_over_limit, csize)) 1886 if (mem_cgroup_margin(mem_over_limit) >= csize)
1902 return CHARGE_RETRY; 1887 return CHARGE_RETRY;
1903 /* 1888 /*
1904 * Even though the limit is exceeded at this point, reclaim 1889 * Even though the limit is exceeded at this point, reclaim