diff options
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 6f5c0c517c49..26e2999af608 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -3260,6 +3260,60 @@ static u64 mem_cgroup_read_u64(struct cgroup_subsys_state *css, | |||
3260 | } | 3260 | } |
3261 | } | 3261 | } |
3262 | 3262 | ||
3263 | static void memcg_flush_percpu_vmstats(struct mem_cgroup *memcg) | ||
3264 | { | ||
3265 | unsigned long stat[MEMCG_NR_STAT]; | ||
3266 | struct mem_cgroup *mi; | ||
3267 | int node, cpu, i; | ||
3268 | |||
3269 | for (i = 0; i < MEMCG_NR_STAT; i++) | ||
3270 | stat[i] = 0; | ||
3271 | |||
3272 | for_each_online_cpu(cpu) | ||
3273 | for (i = 0; i < MEMCG_NR_STAT; i++) | ||
3274 | stat[i] += raw_cpu_read(memcg->vmstats_percpu->stat[i]); | ||
3275 | |||
3276 | for (mi = memcg; mi; mi = parent_mem_cgroup(mi)) | ||
3277 | for (i = 0; i < MEMCG_NR_STAT; i++) | ||
3278 | atomic_long_add(stat[i], &mi->vmstats[i]); | ||
3279 | |||
3280 | for_each_node(node) { | ||
3281 | struct mem_cgroup_per_node *pn = memcg->nodeinfo[node]; | ||
3282 | struct mem_cgroup_per_node *pi; | ||
3283 | |||
3284 | for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) | ||
3285 | stat[i] = 0; | ||
3286 | |||
3287 | for_each_online_cpu(cpu) | ||
3288 | for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) | ||
3289 | stat[i] += raw_cpu_read( | ||
3290 | pn->lruvec_stat_cpu->count[i]); | ||
3291 | |||
3292 | for (pi = pn; pi; pi = parent_nodeinfo(pi, node)) | ||
3293 | for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) | ||
3294 | atomic_long_add(stat[i], &pi->lruvec_stat[i]); | ||
3295 | } | ||
3296 | } | ||
3297 | |||
3298 | static void memcg_flush_percpu_vmevents(struct mem_cgroup *memcg) | ||
3299 | { | ||
3300 | unsigned long events[NR_VM_EVENT_ITEMS]; | ||
3301 | struct mem_cgroup *mi; | ||
3302 | int cpu, i; | ||
3303 | |||
3304 | for (i = 0; i < NR_VM_EVENT_ITEMS; i++) | ||
3305 | events[i] = 0; | ||
3306 | |||
3307 | for_each_online_cpu(cpu) | ||
3308 | for (i = 0; i < NR_VM_EVENT_ITEMS; i++) | ||
3309 | events[i] += raw_cpu_read( | ||
3310 | memcg->vmstats_percpu->events[i]); | ||
3311 | |||
3312 | for (mi = memcg; mi; mi = parent_mem_cgroup(mi)) | ||
3313 | for (i = 0; i < NR_VM_EVENT_ITEMS; i++) | ||
3314 | atomic_long_add(events[i], &mi->vmevents[i]); | ||
3315 | } | ||
3316 | |||
3263 | #ifdef CONFIG_MEMCG_KMEM | 3317 | #ifdef CONFIG_MEMCG_KMEM |
3264 | static int memcg_online_kmem(struct mem_cgroup *memcg) | 3318 | static int memcg_online_kmem(struct mem_cgroup *memcg) |
3265 | { | 3319 | { |
@@ -4682,6 +4736,12 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg) | |||
4682 | { | 4736 | { |
4683 | int node; | 4737 | int node; |
4684 | 4738 | ||
4739 | /* | ||
4740 | * Flush percpu vmstats and vmevents to guarantee the value correctness | ||
4741 | * on parent's and all ancestor levels. | ||
4742 | */ | ||
4743 | memcg_flush_percpu_vmstats(memcg); | ||
4744 | memcg_flush_percpu_vmevents(memcg); | ||
4685 | for_each_node(node) | 4745 | for_each_node(node) |
4686 | free_mem_cgroup_per_node_info(memcg, node); | 4746 | free_mem_cgroup_per_node_info(memcg, node); |
4687 | free_percpu(memcg->vmstats_percpu); | 4747 | free_percpu(memcg->vmstats_percpu); |