Commit 10bf2f7e authored by Vladimir Davydov's avatar Vladimir Davydov Committed by Tejun Heo

cgroup: fix fail path in cgroup_load_subsys()

Calling cgroup_unload_subsys() from cgroup_load_subsys() after
online_css() failure will result in a NULL ptr dereference on attempt to
offline_css(), because online_css() only assigns css to cgroup on
success. Let's fix that by skipping calls to offline_css() and
css_free() in cgroup_unload_subsys() if there is no css, and freeing css
in cgroup_load_subsys() on online_css() failure.
Signed-off-by: default avatarVladimir Davydov <vdavydov@parallels.com>
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Acked-by: default avatarLi Zefan <lizefan@huawei.com>
parent 0be8669d
...@@ -4652,8 +4652,10 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss) ...@@ -4652,8 +4652,10 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
write_unlock(&css_set_lock); write_unlock(&css_set_lock);
ret = online_css(css); ret = online_css(css);
if (ret) if (ret) {
ss->css_free(css);
goto err_unload; goto err_unload;
}
/* success! */ /* success! */
mutex_unlock(&cgroup_root_mutex); mutex_unlock(&cgroup_root_mutex);
...@@ -4680,6 +4682,7 @@ EXPORT_SYMBOL_GPL(cgroup_load_subsys); ...@@ -4680,6 +4682,7 @@ EXPORT_SYMBOL_GPL(cgroup_load_subsys);
void cgroup_unload_subsys(struct cgroup_subsys *ss) void cgroup_unload_subsys(struct cgroup_subsys *ss)
{ {
struct cgrp_cset_link *link; struct cgrp_cset_link *link;
struct cgroup_subsys_state *css;
BUG_ON(ss->module == NULL); BUG_ON(ss->module == NULL);
...@@ -4693,7 +4696,9 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss) ...@@ -4693,7 +4696,9 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)
mutex_lock(&cgroup_mutex); mutex_lock(&cgroup_mutex);
mutex_lock(&cgroup_root_mutex); mutex_lock(&cgroup_root_mutex);
offline_css(cgroup_css(cgroup_dummy_top, ss)); css = cgroup_css(cgroup_dummy_top, ss);
if (css)
offline_css(css);
/* deassign the subsys_id */ /* deassign the subsys_id */
cgroup_subsys[ss->subsys_id] = NULL; cgroup_subsys[ss->subsys_id] = NULL;
...@@ -4720,7 +4725,8 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss) ...@@ -4720,7 +4725,8 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)
* need to free before marking as null because ss->css_free needs * need to free before marking as null because ss->css_free needs
* the cgrp->subsys pointer to find their state. * the cgrp->subsys pointer to find their state.
*/ */
ss->css_free(cgroup_css(cgroup_dummy_top, ss)); if (css)
ss->css_free(css);
RCU_INIT_POINTER(cgroup_dummy_top->subsys[ss->subsys_id], NULL); RCU_INIT_POINTER(cgroup_dummy_top->subsys[ss->subsys_id], NULL);
mutex_unlock(&cgroup_root_mutex); mutex_unlock(&cgroup_root_mutex);
......
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