aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Weiner <hannes@cmpxchg.org>2014-10-02 19:16:57 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-02 19:28:44 -0400
commit2f7dd7a4100ad4affcb141605bef178ab98ccb18 (patch)
tree173b2cf20ce890bbeeb740cfac53b2ba5b859982
parent55dacd22dba7da4d4f2ccd646cd77886e2c90dd1 (diff)
mm: memcontrol: do not iterate uninitialized memcgs
The cgroup iterators yield css objects that have not yet gone through css_online(), but they are not complete memcgs at this point and so the memcg iterators should not return them. Commit d8ad30559715 ("mm/memcg: iteration skip memcgs not yet fully initialized") set out to implement exactly this, but it uses CSS_ONLINE, a cgroup-internal flag that does not meet the ordering requirements for memcg, and so the iterator may skip over initialized groups, or return partially initialized memcgs. The cgroup core can not reasonably provide a clear answer on whether the object around the css has been fully initialized, as that depends on controller-specific locking and lifetime rules. Thus, introduce a memcg-specific flag that is set after the memcg has been initialized in css_online(), and read before mem_cgroup_iter() callers access the memcg members. Signed-off-by: Johannes Weiner <hannes@cmpxchg.org> Cc: Tejun Heo <tj@kernel.org> Acked-by: Michal Hocko <mhocko@suse.cz> Cc: Hugh Dickins <hughd@google.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: <stable@vger.kernel.org> [3.12+] Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/memcontrol.c36
1 files changed, 31 insertions, 5 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 085dc6d2f876..28928ce9b07f 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -292,6 +292,9 @@ struct mem_cgroup {
292 /* vmpressure notifications */ 292 /* vmpressure notifications */
293 struct vmpressure vmpressure; 293 struct vmpressure vmpressure;
294 294
295 /* css_online() has been completed */
296 int initialized;
297
295 /* 298 /*
296 * the counter to account for mem+swap usage. 299 * the counter to account for mem+swap usage.
297 */ 300 */
@@ -1099,10 +1102,21 @@ skip_node:
1099 * skipping css reference should be safe. 1102 * skipping css reference should be safe.
1100 */ 1103 */
1101 if (next_css) { 1104 if (next_css) {
1102 if ((next_css == &root->css) || 1105 struct mem_cgroup *memcg = mem_cgroup_from_css(next_css);
1103 ((next_css->flags & CSS_ONLINE) && 1106
1104 css_tryget_online(next_css))) 1107 if (next_css == &root->css)
1105 return mem_cgroup_from_css(next_css); 1108 return memcg;
1109
1110 if (css_tryget_online(next_css)) {
1111 /*
1112 * Make sure the memcg is initialized:
1113 * mem_cgroup_css_online() orders the the
1114 * initialization against setting the flag.
1115 */
1116 if (smp_load_acquire(&memcg->initialized))
1117 return memcg;
1118 css_put(next_css);
1119 }
1106 1120
1107 prev_css = next_css; 1121 prev_css = next_css;
1108 goto skip_node; 1122 goto skip_node;
@@ -5549,6 +5563,7 @@ mem_cgroup_css_online(struct cgroup_subsys_state *css)
5549{ 5563{
5550 struct mem_cgroup *memcg = mem_cgroup_from_css(css); 5564 struct mem_cgroup *memcg = mem_cgroup_from_css(css);
5551 struct mem_cgroup *parent = mem_cgroup_from_css(css->parent); 5565 struct mem_cgroup *parent = mem_cgroup_from_css(css->parent);
5566 int ret;
5552 5567
5553 if (css->id > MEM_CGROUP_ID_MAX) 5568 if (css->id > MEM_CGROUP_ID_MAX)
5554 return -ENOSPC; 5569 return -ENOSPC;
@@ -5585,7 +5600,18 @@ mem_cgroup_css_online(struct cgroup_subsys_state *css)
5585 } 5600 }
5586 mutex_unlock(&memcg_create_mutex); 5601 mutex_unlock(&memcg_create_mutex);
5587 5602
5588 return memcg_init_kmem(memcg, &memory_cgrp_subsys); 5603 ret = memcg_init_kmem(memcg, &memory_cgrp_subsys);
5604 if (ret)
5605 return ret;
5606
5607 /*
5608 * Make sure the memcg is initialized: mem_cgroup_iter()
5609 * orders reading memcg->initialized against its callers
5610 * reading the memcg members.
5611 */
5612 smp_store_release(&memcg->initialized, 1);
5613
5614 return 0;
5589} 5615}
5590 5616
5591/* 5617/*