aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorVladimir Davydov <vdavydov@parallels.com>2014-01-23 18:53:08 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-23 19:36:51 -0500
commit6de64beb3435ab8f2ac1428dd7dddad5dc679c4b (patch)
treeab6d2832713955cd5bc366ae5bee7dd055183b27 /mm
parentf8570263ee16eb1d5038b8e20d7db3a68bbb2b49 (diff)
memcg: remove KMEM_ACCOUNTED_ACTIVATED flag
Currently we have two state bits in mem_cgroup::kmem_account_flags regarding kmem accounting activation, ACTIVATED and ACTIVE. We start kmem accounting only if both flags are set (memcg_can_account_kmem()), plus throughout the code there are several places where we check only the ACTIVE flag, but we never check the ACTIVATED flag alone. These flags are both set from memcg_update_kmem_limit() under the set_limit_mutex, the ACTIVE flag always being set after ACTIVATED, and they never get cleared. That said checking if both flags are set is equivalent to checking only for the ACTIVE flag, and since there is no ACTIVATED flag checks, we can safely remove the ACTIVATED flag, and nothing will change. Let's try to understand what was the reason for introducing these flags. The purpose of the ACTIVE flag is clear - it states that kmem should be accounting to the cgroup. The only requirement for it is that it should be set after we have fully initialized kmem accounting bits for the cgroup and patched all static branches relating to kmem accounting. Since we always check if static branch is enabled before actually considering if we should account (otherwise we wouldn't benefit from static branching), this guarantees us that we won't skip a commit or uncharge after a charge due to an unpatched static branch. Now let's move on to the ACTIVATED bit. As I proved in the beginning of this message, it is absolutely useless, and removing it will change nothing. So what was the reason introducing it? The ACTIVATED flag was introduced by commit a8964b9b84f9 ("memcg: use static branches when code not in use") in order to guarantee that static_key_slow_inc(&memcg_kmem_enabled_key) would be called only once for each memory cgroup when its kmem accounting was activated. The point was that at that time the memcg_update_kmem_limit() function's work-flow looked like this: bool must_inc_static_branch = false; cgroup_lock(); mutex_lock(&set_limit_mutex); if (!memcg->kmem_account_flags && val != RESOURCE_MAX) { /* The kmem limit is set for the first time */ ret = res_counter_set_limit(&memcg->kmem, val); memcg_kmem_set_activated(memcg); must_inc_static_branch = true; } else ret = res_counter_set_limit(&memcg->kmem, val); mutex_unlock(&set_limit_mutex); cgroup_unlock(); if (must_inc_static_branch) { /* We can't do this under cgroup_lock */ static_key_slow_inc(&memcg_kmem_enabled_key); memcg_kmem_set_active(memcg); } So that without the ACTIVATED flag we could race with other threads trying to set the limit and increment the static branching ref-counter more than once. Today we call the whole memcg_update_kmem_limit() function under the set_limit_mutex and this race is impossible. As now we understand why the ACTIVATED bit was introduced and why we don't need it now, and know that removing it will change nothing anyway, let's get rid of it. Signed-off-by: Vladimir Davydov <vdavydov@parallels.com> Cc: Michal Hocko <mhocko@suse.cz> Cc: Glauber Costa <glommer@gmail.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Balbir Singh <bsingharora@gmail.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/memcontrol.c29
1 files changed, 2 insertions, 27 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 216659d4441a..706f7bc16db2 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -382,15 +382,10 @@ struct mem_cgroup {
382 382
383/* internal only representation about the status of kmem accounting. */ 383/* internal only representation about the status of kmem accounting. */
384enum { 384enum {
385 KMEM_ACCOUNTED_ACTIVE = 0, /* accounted by this cgroup itself */ 385 KMEM_ACCOUNTED_ACTIVE, /* accounted by this cgroup itself */
386 KMEM_ACCOUNTED_ACTIVATED, /* static key enabled. */
387 KMEM_ACCOUNTED_DEAD, /* dead memcg with pending kmem charges */ 386 KMEM_ACCOUNTED_DEAD, /* dead memcg with pending kmem charges */
388}; 387};
389 388
390/* We account when limit is on, but only after call sites are patched */
391#define KMEM_ACCOUNTED_MASK \
392 ((1 << KMEM_ACCOUNTED_ACTIVE) | (1 << KMEM_ACCOUNTED_ACTIVATED))
393
394#ifdef CONFIG_MEMCG_KMEM 389#ifdef CONFIG_MEMCG_KMEM
395static inline void memcg_kmem_set_active(struct mem_cgroup *memcg) 390static inline void memcg_kmem_set_active(struct mem_cgroup *memcg)
396{ 391{
@@ -402,16 +397,6 @@ static bool memcg_kmem_is_active(struct mem_cgroup *memcg)
402 return test_bit(KMEM_ACCOUNTED_ACTIVE, &memcg->kmem_account_flags); 397 return test_bit(KMEM_ACCOUNTED_ACTIVE, &memcg->kmem_account_flags);
403} 398}
404 399
405static void memcg_kmem_set_activated(struct mem_cgroup *memcg)
406{
407 set_bit(KMEM_ACCOUNTED_ACTIVATED, &memcg->kmem_account_flags);
408}
409
410static void memcg_kmem_clear_activated(struct mem_cgroup *memcg)
411{
412 clear_bit(KMEM_ACCOUNTED_ACTIVATED, &memcg->kmem_account_flags);
413}
414
415static void memcg_kmem_mark_dead(struct mem_cgroup *memcg) 400static void memcg_kmem_mark_dead(struct mem_cgroup *memcg)
416{ 401{
417 /* 402 /*
@@ -2995,8 +2980,7 @@ static DEFINE_MUTEX(set_limit_mutex);
2995static inline bool memcg_can_account_kmem(struct mem_cgroup *memcg) 2980static inline bool memcg_can_account_kmem(struct mem_cgroup *memcg)
2996{ 2981{
2997 return !mem_cgroup_disabled() && !mem_cgroup_is_root(memcg) && 2982 return !mem_cgroup_disabled() && !mem_cgroup_is_root(memcg) &&
2998 (memcg->kmem_account_flags & KMEM_ACCOUNTED_MASK) == 2983 memcg_kmem_is_active(memcg);
2999 KMEM_ACCOUNTED_MASK;
3000} 2984}
3001 2985
3002/* 2986/*
@@ -3120,19 +3104,10 @@ static int memcg_update_cache_sizes(struct mem_cgroup *memcg)
3120 0, MEMCG_CACHES_MAX_SIZE, GFP_KERNEL); 3104 0, MEMCG_CACHES_MAX_SIZE, GFP_KERNEL);
3121 if (num < 0) 3105 if (num < 0)
3122 return num; 3106 return num;
3123 /*
3124 * After this point, kmem_accounted (that we test atomically in
3125 * the beginning of this conditional), is no longer 0. This
3126 * guarantees only one process will set the following boolean
3127 * to true. We don't need test_and_set because we're protected
3128 * by the set_limit_mutex anyway.
3129 */
3130 memcg_kmem_set_activated(memcg);
3131 3107
3132 ret = memcg_update_all_caches(num+1); 3108 ret = memcg_update_all_caches(num+1);
3133 if (ret) { 3109 if (ret) {
3134 ida_simple_remove(&kmem_limited_groups, num); 3110 ida_simple_remove(&kmem_limited_groups, num);
3135 memcg_kmem_clear_activated(memcg);
3136 return ret; 3111 return ret;
3137 } 3112 }
3138 3113