Commit 9c56751271e7a917783fb57ec49fe8382e0dc867

Authored by David Rientjes
Committed by Linus Torvalds
1 parent 34ec4de42b

mm, memcg: protect mem_cgroup_read_events for cpu hotplug

for_each_online_cpu() needs the protection of {get,put}_online_cpus() so
cpu_online_mask doesn't change during the iteration.

cpu_hotplug.lock is held while a cpu is going down, it's a coarse lock
that is used kernel-wide to synchronize cpu hotplug activity.  Memcg has
a cpu hotplug notifier, called while there may not be any cpu hotplug
refcounts, which drains per-cpu event counts to memcg->nocpu_base.events
to maintain a cumulative event count as cpus disappear.  Without
get_online_cpus() in mem_cgroup_read_events(), it's possible to account
for the event count on a dying cpu twice, and this value may be
significantly large.

In fact, all memcg->pcp_counter_lock use should be nested by
{get,put}_online_cpus().

This fixes that issue and ensures the reported statistics are not vastly
over-reported during cpu hotplug.

Signed-off-by: David Rientjes <rientjes@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@suse.cz>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Acked-by: 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 1 changed file with 2 additions and 0 deletions Side-by-side Diff

... ... @@ -866,6 +866,7 @@
866 866 unsigned long val = 0;
867 867 int cpu;
868 868  
  869 + get_online_cpus();
869 870 for_each_online_cpu(cpu)
870 871 val += per_cpu(memcg->stat->events[idx], cpu);
871 872 #ifdef CONFIG_HOTPLUG_CPU
... ... @@ -873,6 +874,7 @@
873 874 val += memcg->nocpu_base.events[idx];
874 875 spin_unlock(&memcg->pcp_counter_lock);
875 876 #endif
  877 + put_online_cpus();
876 878 return val;
877 879 }
878 880