diff options
author | Greg Thelen <gthelen@google.com> | 2013-11-01 15:16:59 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-01 15:22:28 -0400 |
commit | 6920a1bd037374a632d585de127b6f945199dcb8 (patch) | |
tree | db8e26fd7c5758ce2747b98f4ec7e1af32198740 /mm/memcontrol.c | |
parent | 4f794ee8c40119366e0be45f9d49e7ff1a89b79b (diff) |
memcg: remove incorrect underflow check
When a memcg is deleted mem_cgroup_reparent_charges() moves charged
memory to the parent memcg. As of v3.11-9444-g3ea67d0 "memcg: add per
cgroup writeback pages accounting" there's bad pointer read. The goal
was to check for counter underflow. The counter is a per cpu counter
and there are two problems with the code:
(1) per cpu access function isn't used, instead a naked pointer is used
which easily causes oops.
(2) the check doesn't sum all cpus
Test:
$ cd /sys/fs/cgroup/memory
$ mkdir x
$ echo 3 > /proc/sys/vm/drop_caches
$ (echo $BASHPID >> x/tasks && exec cat) &
[1] 7154
$ grep ^mapped x/memory.stat
mapped_file 53248
$ echo 7154 > tasks
$ rmdir x
<OOPS>
The fix is to remove the check. It's currently dangerous and isn't
worth fixing it to use something expensive, such as
percpu_counter_sum(), for each reparented page. __this_cpu_read() isn't
enough to fix this because there's no guarantees of the current cpus
count. The only guarantees is that the sum of all per-cpu counter is >=
nr_pages.
Fixes: 3ea67d06e467 ("memcg: add per cgroup writeback pages accounting")
Reported-and-tested-by: Flavio Leitner <fbl@redhat.com>
Signed-off-by: Greg Thelen <gthelen@google.com>
Reviewed-by: Sha Zhengju <handai.szj@taobao.com>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: Hugh Dickins <hughd@google.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 1 |
1 files changed, 0 insertions, 1 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index e63278222be5..13b9d0f221b8 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -3782,7 +3782,6 @@ void mem_cgroup_move_account_page_stat(struct mem_cgroup *from, | |||
3782 | { | 3782 | { |
3783 | /* Update stat data for mem_cgroup */ | 3783 | /* Update stat data for mem_cgroup */ |
3784 | preempt_disable(); | 3784 | preempt_disable(); |
3785 | WARN_ON_ONCE(from->stat->count[idx] < nr_pages); | ||
3786 | __this_cpu_sub(from->stat->count[idx], nr_pages); | 3785 | __this_cpu_sub(from->stat->count[idx], nr_pages); |
3787 | __this_cpu_add(to->stat->count[idx], nr_pages); | 3786 | __this_cpu_add(to->stat->count[idx], nr_pages); |
3788 | preempt_enable(); | 3787 | preempt_enable(); |