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: Li Zefan <lizefan@huawei.com> Acked-by: Glauber Costa <glommer@parallels.com> Acked-by: Michal Hocko <mhocko@suse.cz> Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
ebff7d8f27
commit
ca0dde9717
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue