diff options
author | Tejun Heo <tj@kernel.org> | 2012-11-19 11:13:37 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2012-11-19 11:13:37 -0500 |
commit | d19e19de48aa0b90c56cd93c8a46ebac46273429 (patch) | |
tree | ea485692e0b5a7fdfa6bf6a80558957e89b220c2 /kernel/cgroup.c | |
parent | a31f2d3ff7fe20cbe2a143515a7d7c408b29dd0d (diff) |
cgroup: simplify cgroup_load_subsys() failure path
Now that cgroup_unload_subsys() can tell whether the root css is
online or not, we can safely call cgroup_unload_subsys() after idr
init failure in cgroup_load_subsys().
Replace the manual unrolling and invoke cgroup_unload_subsys() on
failure. This drops cgroup_mutex inbetween but should be safe as the
subsystem will fail try_module_get() and thus can't be mounted
inbetween. As this means that cgroup_unload_subsys() can be called
before css_sets are rehashed, remove BUG_ON() on %NULL
css_set->subsys[] from cgroup_unload_subsys().
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Li Zefan <lizefan@huawei.com>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 21 |
1 files changed, 10 insertions, 11 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 78a3d5c0968e..166b5141f3d4 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -4400,8 +4400,8 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss) | |||
4400 | */ | 4400 | */ |
4401 | int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss) | 4401 | int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss) |
4402 | { | 4402 | { |
4403 | int i; | ||
4404 | struct cgroup_subsys_state *css; | 4403 | struct cgroup_subsys_state *css; |
4404 | int i, ret; | ||
4405 | 4405 | ||
4406 | /* check name and function validity */ | 4406 | /* check name and function validity */ |
4407 | if (ss->name == NULL || strlen(ss->name) > MAX_CGROUP_TYPE_NAMELEN || | 4407 | if (ss->name == NULL || strlen(ss->name) > MAX_CGROUP_TYPE_NAMELEN || |
@@ -4452,15 +4452,9 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss) | |||
4452 | init_cgroup_css(css, ss, dummytop); | 4452 | init_cgroup_css(css, ss, dummytop); |
4453 | /* init_idr must be after init_cgroup_css because it sets css->id. */ | 4453 | /* init_idr must be after init_cgroup_css because it sets css->id. */ |
4454 | if (ss->use_id) { | 4454 | if (ss->use_id) { |
4455 | int ret = cgroup_init_idr(ss, css); | 4455 | ret = cgroup_init_idr(ss, css); |
4456 | if (ret) { | 4456 | if (ret) |
4457 | ss->destroy(dummytop); | 4457 | goto err_unload; |
4458 | dummytop->subsys[ss->subsys_id] = NULL; | ||
4459 | subsys[ss->subsys_id] = NULL; | ||
4460 | list_del_init(&ss->sibling); | ||
4461 | mutex_unlock(&cgroup_mutex); | ||
4462 | return ret; | ||
4463 | } | ||
4464 | } | 4458 | } |
4465 | 4459 | ||
4466 | /* | 4460 | /* |
@@ -4498,6 +4492,12 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss) | |||
4498 | /* success! */ | 4492 | /* success! */ |
4499 | mutex_unlock(&cgroup_mutex); | 4493 | mutex_unlock(&cgroup_mutex); |
4500 | return 0; | 4494 | return 0; |
4495 | |||
4496 | err_unload: | ||
4497 | mutex_unlock(&cgroup_mutex); | ||
4498 | /* @ss can't be mounted here as try_module_get() would fail */ | ||
4499 | cgroup_unload_subsys(ss); | ||
4500 | return ret; | ||
4501 | } | 4501 | } |
4502 | EXPORT_SYMBOL_GPL(cgroup_load_subsys); | 4502 | EXPORT_SYMBOL_GPL(cgroup_load_subsys); |
4503 | 4503 | ||
@@ -4548,7 +4548,6 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss) | |||
4548 | struct css_set *cg = link->cg; | 4548 | struct css_set *cg = link->cg; |
4549 | 4549 | ||
4550 | hlist_del(&cg->hlist); | 4550 | hlist_del(&cg->hlist); |
4551 | BUG_ON(!cg->subsys[ss->subsys_id]); | ||
4552 | cg->subsys[ss->subsys_id] = NULL; | 4551 | cg->subsys[ss->subsys_id] = NULL; |
4553 | hhead = css_set_hash(cg->subsys); | 4552 | hhead = css_set_hash(cg->subsys); |
4554 | hlist_add_head(&cg->hlist, hhead); | 4553 | hlist_add_head(&cg->hlist, hhead); |