memcg: add RCU locking around css_for_each_descendant_pre() in memcg_offline_kmem()
memcg_offline_kmem() may be called from memcg_free_kmem() after a css init failure. memcg_free_kmem() is a ->css_free callback which is called without cgroup_mutex and memcg_offline_kmem() ends up using css_for_each_descendant_pre() without any locking. Fix it by adding rcu read locking around it. mkdir: cannot create directory `65530': No space left on device =============================== [ INFO: suspicious RCU usage. ] 4.6.0-work+ #321 Not tainted ------------------------------- kernel/cgroup.c:4008 cgroup_mutex or RCU read lock required! [ 527.243970] other info that might help us debug this: [ 527.244715] rcu_scheduler_active = 1, debug_locks = 0 2 locks held by kworker/0:5/1664: #0: ("cgroup_destroy"){.+.+..}, at: [<ffffffff81060ab5>] process_one_work+0x165/0x4a0 #1: ((&css->destroy_work)#3){+.+...}, at: [<ffffffff81060ab5>] process_one_work+0x165/0x4a0 [ 527.248098] stack backtrace: CPU: 0 PID: 1664 Comm: kworker/0:5 Not tainted 4.6.0-work+ #321 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.9.1-1.fc24 04/01/2014 Workqueue: cgroup_destroy css_free_work_fn Call Trace: dump_stack+0x68/0xa1 lockdep_rcu_suspicious+0xd7/0x110 css_next_descendant_pre+0x7d/0xb0 memcg_offline_kmem.part.44+0x4a/0xc0 mem_cgroup_css_free+0x1ec/0x200 css_free_work_fn+0x49/0x5e0 process_one_work+0x1c5/0x4a0 worker_thread+0x49/0x490 kthread+0xea/0x100 ret_from_fork+0x1f/0x40 Link: http://lkml.kernel.org/r/20160526203018.GG23194@mtj.duckdns.org Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Vladimir Davydov <vdavydov@virtuozzo.com> Acked-by: Johannes Weiner <hannes@cmpxchg.org> Cc: Michal Hocko <mhocko@kernel.org> Cc: <stable@vger.kernel.org> [4.5+] Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Родитель
f86e427197
Коммит
3a06bb78ce
|
@ -2896,6 +2896,7 @@ static void memcg_offline_kmem(struct mem_cgroup *memcg)
|
||||||
* ordering is imposed by list_lru_node->lock taken by
|
* ordering is imposed by list_lru_node->lock taken by
|
||||||
* memcg_drain_all_list_lrus().
|
* memcg_drain_all_list_lrus().
|
||||||
*/
|
*/
|
||||||
|
rcu_read_lock(); /* can be called from css_free w/o cgroup_mutex */
|
||||||
css_for_each_descendant_pre(css, &memcg->css) {
|
css_for_each_descendant_pre(css, &memcg->css) {
|
||||||
child = mem_cgroup_from_css(css);
|
child = mem_cgroup_from_css(css);
|
||||||
BUG_ON(child->kmemcg_id != kmemcg_id);
|
BUG_ON(child->kmemcg_id != kmemcg_id);
|
||||||
|
@ -2903,6 +2904,8 @@ static void memcg_offline_kmem(struct mem_cgroup *memcg)
|
||||||
if (!memcg->use_hierarchy)
|
if (!memcg->use_hierarchy)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
memcg_drain_all_list_lrus(kmemcg_id, parent->kmemcg_id);
|
memcg_drain_all_list_lrus(kmemcg_id, parent->kmemcg_id);
|
||||||
|
|
||||||
memcg_free_cache_id(kmemcg_id);
|
memcg_free_cache_id(kmemcg_id);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче