mm: memcontrol: flush percpu vmevents before releasing memcg
[sfrench/cifs-2.6.git] / mm / memcontrol.c
index 1a32e32e7ac3ae3324808d2274951c42569b960b..26e2999af608d3776e609b213d522345fc793792 100644 (file)
@@ -3295,6 +3295,25 @@ static void memcg_flush_percpu_vmstats(struct mem_cgroup *memcg)
        }
 }
 
+static void memcg_flush_percpu_vmevents(struct mem_cgroup *memcg)
+{
+       unsigned long events[NR_VM_EVENT_ITEMS];
+       struct mem_cgroup *mi;
+       int cpu, i;
+
+       for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
+               events[i] = 0;
+
+       for_each_online_cpu(cpu)
+               for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
+                       events[i] += raw_cpu_read(
+                               memcg->vmstats_percpu->events[i]);
+
+       for (mi = memcg; mi; mi = parent_mem_cgroup(mi))
+               for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
+                       atomic_long_add(events[i], &mi->vmevents[i]);
+}
+
 #ifdef CONFIG_MEMCG_KMEM
 static int memcg_online_kmem(struct mem_cgroup *memcg)
 {
@@ -4718,10 +4737,11 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg)
        int node;
 
        /*
-        * Flush percpu vmstats to guarantee the value correctness
+        * Flush percpu vmstats and vmevents to guarantee the value correctness
         * on parent's and all ancestor levels.
         */
        memcg_flush_percpu_vmstats(memcg);
+       memcg_flush_percpu_vmevents(memcg);
        for_each_node(node)
                free_mem_cgroup_per_node_info(memcg, node);
        free_percpu(memcg->vmstats_percpu);