diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/memcontrol.c | 66 |
1 files changed, 34 insertions, 32 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index f96ccc90fa6..e16694d5e11 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -5247,16 +5247,29 @@ out_free: | |||
5247 | } | 5247 | } |
5248 | 5248 | ||
5249 | /* | 5249 | /* |
5250 | * Helpers for freeing a kmalloc()ed/vzalloc()ed mem_cgroup by RCU, | 5250 | * At destroying mem_cgroup, references from swap_cgroup can remain. |
5251 | * but in process context. The work_freeing structure is overlaid | 5251 | * (scanning all at force_empty is too costly...) |
5252 | * on the rcu_freeing structure, which itself is overlaid on memsw. | 5252 | * |
5253 | * Instead of clearing all references at force_empty, we remember | ||
5254 | * the number of reference from swap_cgroup and free mem_cgroup when | ||
5255 | * it goes down to 0. | ||
5256 | * | ||
5257 | * Removal of cgroup itself succeeds regardless of refs from swap. | ||
5253 | */ | 5258 | */ |
5254 | static void free_work(struct work_struct *work) | 5259 | |
5260 | static void __mem_cgroup_free(struct mem_cgroup *memcg) | ||
5255 | { | 5261 | { |
5256 | struct mem_cgroup *memcg; | 5262 | int node; |
5257 | int size = sizeof(struct mem_cgroup); | 5263 | int size = sizeof(struct mem_cgroup); |
5258 | 5264 | ||
5259 | memcg = container_of(work, struct mem_cgroup, work_freeing); | 5265 | mem_cgroup_remove_from_trees(memcg); |
5266 | free_css_id(&mem_cgroup_subsys, &memcg->css); | ||
5267 | |||
5268 | for_each_node(node) | ||
5269 | free_mem_cgroup_per_zone_info(memcg, node); | ||
5270 | |||
5271 | free_percpu(memcg->stat); | ||
5272 | |||
5260 | /* | 5273 | /* |
5261 | * We need to make sure that (at least for now), the jump label | 5274 | * We need to make sure that (at least for now), the jump label |
5262 | * destruction code runs outside of the cgroup lock. This is because | 5275 | * destruction code runs outside of the cgroup lock. This is because |
@@ -5275,38 +5288,27 @@ static void free_work(struct work_struct *work) | |||
5275 | vfree(memcg); | 5288 | vfree(memcg); |
5276 | } | 5289 | } |
5277 | 5290 | ||
5278 | static void free_rcu(struct rcu_head *rcu_head) | ||
5279 | { | ||
5280 | struct mem_cgroup *memcg; | ||
5281 | |||
5282 | memcg = container_of(rcu_head, struct mem_cgroup, rcu_freeing); | ||
5283 | INIT_WORK(&memcg->work_freeing, free_work); | ||
5284 | schedule_work(&memcg->work_freeing); | ||
5285 | } | ||
5286 | 5291 | ||
5287 | /* | 5292 | /* |
5288 | * At destroying mem_cgroup, references from swap_cgroup can remain. | 5293 | * Helpers for freeing a kmalloc()ed/vzalloc()ed mem_cgroup by RCU, |
5289 | * (scanning all at force_empty is too costly...) | 5294 | * but in process context. The work_freeing structure is overlaid |
5290 | * | 5295 | * on the rcu_freeing structure, which itself is overlaid on memsw. |
5291 | * Instead of clearing all references at force_empty, we remember | ||
5292 | * the number of reference from swap_cgroup and free mem_cgroup when | ||
5293 | * it goes down to 0. | ||
5294 | * | ||
5295 | * Removal of cgroup itself succeeds regardless of refs from swap. | ||
5296 | */ | 5296 | */ |
5297 | 5297 | static void free_work(struct work_struct *work) | |
5298 | static void __mem_cgroup_free(struct mem_cgroup *memcg) | ||
5299 | { | 5298 | { |
5300 | int node; | 5299 | struct mem_cgroup *memcg; |
5301 | 5300 | ||
5302 | mem_cgroup_remove_from_trees(memcg); | 5301 | memcg = container_of(work, struct mem_cgroup, work_freeing); |
5303 | free_css_id(&mem_cgroup_subsys, &memcg->css); | 5302 | __mem_cgroup_free(memcg); |
5303 | } | ||
5304 | 5304 | ||
5305 | for_each_node(node) | 5305 | static void free_rcu(struct rcu_head *rcu_head) |
5306 | free_mem_cgroup_per_zone_info(memcg, node); | 5306 | { |
5307 | struct mem_cgroup *memcg; | ||
5307 | 5308 | ||
5308 | free_percpu(memcg->stat); | 5309 | memcg = container_of(rcu_head, struct mem_cgroup, rcu_freeing); |
5309 | call_rcu(&memcg->rcu_freeing, free_rcu); | 5310 | INIT_WORK(&memcg->work_freeing, free_work); |
5311 | schedule_work(&memcg->work_freeing); | ||
5310 | } | 5312 | } |
5311 | 5313 | ||
5312 | static void mem_cgroup_get(struct mem_cgroup *memcg) | 5314 | static void mem_cgroup_get(struct mem_cgroup *memcg) |
@@ -5318,7 +5320,7 @@ static void __mem_cgroup_put(struct mem_cgroup *memcg, int count) | |||
5318 | { | 5320 | { |
5319 | if (atomic_sub_and_test(count, &memcg->refcnt)) { | 5321 | if (atomic_sub_and_test(count, &memcg->refcnt)) { |
5320 | struct mem_cgroup *parent = parent_mem_cgroup(memcg); | 5322 | struct mem_cgroup *parent = parent_mem_cgroup(memcg); |
5321 | __mem_cgroup_free(memcg); | 5323 | call_rcu(&memcg->rcu_freeing, free_rcu); |
5322 | if (parent) | 5324 | if (parent) |
5323 | mem_cgroup_put(parent); | 5325 | mem_cgroup_put(parent); |
5324 | } | 5326 | } |