Commit ca0dde97 authored by Li Zefan's avatar Li Zefan Committed by Linus Torvalds

memcg: take reference before releasing rcu_read_lock

The memcg is not referenced, so it can be destroyed at anytime right
after we exit rcu read section, so it's not safe to access it.

To fix this, we call css_tryget() to get a reference while we're still
in rcu read section.

This also removes a bogus comment above __memcg_create_cache_enqueue().
Signed-off-by: default avatarLi Zefan <lizefan@huawei.com>
Acked-by: default avatarGlauber Costa <glommer@parallels.com>
Acked-by: default avatarMichal Hocko <mhocko@suse.cz>
Acked-by: default avatarKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent ebff7d8f
......@@ -3483,7 +3483,6 @@ static void memcg_create_cache_work_func(struct work_struct *w)
/*
* Enqueue the creation of a per-memcg kmem_cache.
* Called with rcu_read_lock.
*/
static void __memcg_create_cache_enqueue(struct mem_cgroup *memcg,
struct kmem_cache *cachep)
......@@ -3491,12 +3490,8 @@ static void __memcg_create_cache_enqueue(struct mem_cgroup *memcg,
struct create_work *cw;
cw = kmalloc(sizeof(struct create_work), GFP_NOWAIT);
if (cw == NULL)
return;
/* The corresponding put will be done in the workqueue. */
if (!css_tryget(&memcg->css)) {
kfree(cw);
if (cw == NULL) {
css_put(&memcg->css);
return;
}
......@@ -3552,10 +3547,9 @@ struct kmem_cache *__memcg_kmem_get_cache(struct kmem_cache *cachep,
rcu_read_lock();
memcg = mem_cgroup_from_task(rcu_dereference(current->mm->owner));
rcu_read_unlock();
if (!memcg_can_account_kmem(memcg))
return cachep;
goto out;
idx = memcg_cache_id(memcg);
......@@ -3564,7 +3558,16 @@ struct kmem_cache *__memcg_kmem_get_cache(struct kmem_cache *cachep,
* code updating memcg_caches will issue a write barrier to match this.
*/
read_barrier_depends();
if (unlikely(cachep->memcg_params->memcg_caches[idx] == NULL)) {
if (likely(cachep->memcg_params->memcg_caches[idx])) {
cachep = cachep->memcg_params->memcg_caches[idx];
goto out;
}
/* The corresponding put will be done in the workqueue. */
if (!css_tryget(&memcg->css))
goto out;
rcu_read_unlock();
/*
* If we are in a safe context (can wait, and not in interrupt
* context), we could be be predictable and return right away.
......@@ -3584,9 +3587,9 @@ struct kmem_cache *__memcg_kmem_get_cache(struct kmem_cache *cachep,
*/
memcg_create_cache_enqueue(memcg, cachep);
return cachep;
}
return cachep->memcg_params->memcg_caches[idx];
out:
rcu_read_unlock();
return cachep;
}
EXPORT_SYMBOL(__memcg_kmem_get_cache);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment