diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-10-06 08:13:18 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-06 08:13:18 +0200 |
commit | 2c10c22af088ab5d94fae93ce3fe6436b2a208b4 (patch) | |
tree | db27721001f194327ddbdcd6c983c4ec68b77c00 /mm/memcontrol.c | |
parent | f6121f4f8708195e88cbdf8dd8d171b226b3f858 (diff) | |
parent | fec6ed1d1f9b78a6acb4a3eb2c46c812ac2e96f0 (diff) |
Merge branch 'linus' into sched/devel
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 0f1f7a7374ba..36896f3eb7f5 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -250,6 +250,14 @@ static struct mem_cgroup *mem_cgroup_from_cont(struct cgroup *cont) struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p) { + /* + * mm_update_next_owner() may clear mm->owner to NULL + * if it races with swapoff, page migration, etc. + * So this can be called with p == NULL. + */ + if (unlikely(!p)) + return NULL; + return container_of(task_subsys_state(p, mem_cgroup_subsys_id), struct mem_cgroup, css); } @@ -549,6 +557,11 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm, if (likely(!memcg)) { rcu_read_lock(); mem = mem_cgroup_from_task(rcu_dereference(mm->owner)); + if (unlikely(!mem)) { + rcu_read_unlock(); + kmem_cache_free(page_cgroup_cache, pc); + return 0; + } /* * For every charge from the cgroup, increment reference count */ @@ -801,11 +814,16 @@ int mem_cgroup_shrink_usage(struct mm_struct *mm, gfp_t gfp_mask) rcu_read_lock(); mem = mem_cgroup_from_task(rcu_dereference(mm->owner)); + if (unlikely(!mem)) { + rcu_read_unlock(); + return 0; + } css_get(&mem->css); rcu_read_unlock(); do { progress = try_to_free_mem_cgroup_pages(mem, gfp_mask); + progress += res_counter_check_under_limit(&mem->res); } while (!progress && --retry); css_put(&mem->css); |