diff options
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index f1a0ae6e11b8..bf5e89457149 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -2694,7 +2694,10 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm, | |||
2694 | goto bypass; | 2694 | goto bypass; |
2695 | 2695 | ||
2696 | if (unlikely(task_in_memcg_oom(current))) | 2696 | if (unlikely(task_in_memcg_oom(current))) |
2697 | goto bypass; | 2697 | goto nomem; |
2698 | |||
2699 | if (gfp_mask & __GFP_NOFAIL) | ||
2700 | oom = false; | ||
2698 | 2701 | ||
2699 | /* | 2702 | /* |
2700 | * We always charge the cgroup the mm_struct belongs to. | 2703 | * We always charge the cgroup the mm_struct belongs to. |
@@ -6352,6 +6355,42 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) | |||
6352 | static void mem_cgroup_css_free(struct cgroup_subsys_state *css) | 6355 | static void mem_cgroup_css_free(struct cgroup_subsys_state *css) |
6353 | { | 6356 | { |
6354 | struct mem_cgroup *memcg = mem_cgroup_from_css(css); | 6357 | struct mem_cgroup *memcg = mem_cgroup_from_css(css); |
6358 | /* | ||
6359 | * XXX: css_offline() would be where we should reparent all | ||
6360 | * memory to prepare the cgroup for destruction. However, | ||
6361 | * memcg does not do css_tryget() and res_counter charging | ||
6362 | * under the same RCU lock region, which means that charging | ||
6363 | * could race with offlining. Offlining only happens to | ||
6364 | * cgroups with no tasks in them but charges can show up | ||
6365 | * without any tasks from the swapin path when the target | ||
6366 | * memcg is looked up from the swapout record and not from the | ||
6367 | * current task as it usually is. A race like this can leak | ||
6368 | * charges and put pages with stale cgroup pointers into | ||
6369 | * circulation: | ||
6370 | * | ||
6371 | * #0 #1 | ||
6372 | * lookup_swap_cgroup_id() | ||
6373 | * rcu_read_lock() | ||
6374 | * mem_cgroup_lookup() | ||
6375 | * css_tryget() | ||
6376 | * rcu_read_unlock() | ||
6377 | * disable css_tryget() | ||
6378 | * call_rcu() | ||
6379 | * offline_css() | ||
6380 | * reparent_charges() | ||
6381 | * res_counter_charge() | ||
6382 | * css_put() | ||
6383 | * css_free() | ||
6384 | * pc->mem_cgroup = dead memcg | ||
6385 | * add page to lru | ||
6386 | * | ||
6387 | * The bulk of the charges are still moved in offline_css() to | ||
6388 | * avoid pinning a lot of pages in case a long-term reference | ||
6389 | * like a swapout record is deferring the css_free() to long | ||
6390 | * after offlining. But this makes sure we catch any charges | ||
6391 | * made after offlining: | ||
6392 | */ | ||
6393 | mem_cgroup_reparent_charges(memcg); | ||
6355 | 6394 | ||
6356 | memcg_destroy_kmem(memcg); | 6395 | memcg_destroy_kmem(memcg); |
6357 | __mem_cgroup_free(memcg); | 6396 | __mem_cgroup_free(memcg); |