diff options
author | Tejun Heo <tj@kernel.org> | 2014-02-12 09:29:50 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2014-02-12 09:29:50 -0500 |
commit | 6f30558f37bfbd428e3854c2c34b5c32117c8f7e (patch) | |
tree | c02c711bf750ea306cc008a787335fedfba7feab /kernel/cgroup.c | |
parent | 21a2d3430ba8c188af405a5c2eb9c06bdcb6add6 (diff) |
cgroup: make cgroup hold onto its kernfs_node
cgroup currently releases its kernfs_node when it gets removed. While
not buggy, this makes cgroup->kn access rules complicated than
necessary and leads to things like get/put protection around
kernfs_remove() in cgroup_destroy_locked(). In addition, we want to
use kernfs_name/path() and friends but also want to be able to
determine a cgroup's name between removal and release.
This patch makes cgroup hold onto its kernfs_node until freed so that
cgroup->kn is always accessible.
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 | 16 |
1 files changed, 9 insertions, 7 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index f4409715a2f5..59dfb025f1ac 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -957,6 +957,8 @@ static void cgroup_free_fn(struct work_struct *work) | |||
957 | 957 | ||
958 | cgroup_pidlist_destroy_all(cgrp); | 958 | cgroup_pidlist_destroy_all(cgrp); |
959 | 959 | ||
960 | kernfs_put(cgrp->kn); | ||
961 | |||
960 | kfree(rcu_dereference_raw(cgrp->name)); | 962 | kfree(rcu_dereference_raw(cgrp->name)); |
961 | kfree(cgrp); | 963 | kfree(cgrp); |
962 | } | 964 | } |
@@ -3786,6 +3788,12 @@ static long cgroup_create(struct cgroup *parent, const char *name_str, | |||
3786 | } | 3788 | } |
3787 | cgrp->kn = kn; | 3789 | cgrp->kn = kn; |
3788 | 3790 | ||
3791 | /* | ||
3792 | * This extra ref will be put in cgroup_free_fn() and guarantees | ||
3793 | * that @cgrp->kn is always accessible. | ||
3794 | */ | ||
3795 | kernfs_get(kn); | ||
3796 | |||
3789 | cgrp->serial_nr = cgroup_serial_nr_next++; | 3797 | cgrp->serial_nr = cgroup_serial_nr_next++; |
3790 | 3798 | ||
3791 | /* allocation complete, commit to creation */ | 3799 | /* allocation complete, commit to creation */ |
@@ -3966,7 +3974,6 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
3966 | { | 3974 | { |
3967 | struct cgroup *child; | 3975 | struct cgroup *child; |
3968 | struct cgroup_subsys_state *css; | 3976 | struct cgroup_subsys_state *css; |
3969 | struct kernfs_node *kn; | ||
3970 | bool empty; | 3977 | bool empty; |
3971 | int ssid; | 3978 | int ssid; |
3972 | 3979 | ||
@@ -4044,13 +4051,8 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
4044 | * clearing of cgrp->kn->priv backpointer, which should happen | 4051 | * clearing of cgrp->kn->priv backpointer, which should happen |
4045 | * after all files under it have been removed. | 4052 | * after all files under it have been removed. |
4046 | */ | 4053 | */ |
4047 | kn = cgrp->kn; | 4054 | kernfs_remove(cgrp->kn); /* @cgrp has an extra ref on its kn */ |
4048 | kernfs_get(kn); | ||
4049 | |||
4050 | kernfs_remove(cgrp->kn); | ||
4051 | |||
4052 | RCU_INIT_POINTER(*(void __rcu __force **)&cgrp->kn->priv, NULL); | 4055 | RCU_INIT_POINTER(*(void __rcu __force **)&cgrp->kn->priv, NULL); |
4053 | kernfs_put(kn); | ||
4054 | 4056 | ||
4055 | mutex_lock(&cgroup_mutex); | 4057 | mutex_lock(&cgroup_mutex); |
4056 | 4058 | ||