diff options
author | Tejun Heo <tj@kernel.org> | 2013-08-26 18:40:56 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-08-26 18:40:56 -0400 |
commit | 7941cb027dccedec3c047271554ddcf4be2e0697 (patch) | |
tree | 72bf50000b99403d9610ac9d32d21900e06c1bc6 /kernel/cgroup.c | |
parent | 9fa4db334c7d9570aec7a5121e84fae99aae1d04 (diff) |
cgroup: make cgroup_event hold onto cgroup_subsys_state instead of cgroup
Currently, each registered cgroup_event holds an extra reference to
the cgroup. This is a bit weird as events are subsystem specific and
will also be incorrect in the planned unified hierarchy as css
(cgroup_subsys_state) may come and go dynamically across the lifetime
of a cgroup. Holding onto cgroup won't prevent the target css from
going away.
Update cgroup_event to hold onto the css the traget file belongs to
instead of cgroup.
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Li Zefan <lizefan@huawei.com>
Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 26 |
1 files changed, 12 insertions, 14 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index a41dc87cd07e..12237a291d88 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -3969,7 +3969,6 @@ static void cgroup_event_remove(struct work_struct *work) | |||
3969 | struct cgroup_event *event = container_of(work, struct cgroup_event, | 3969 | struct cgroup_event *event = container_of(work, struct cgroup_event, |
3970 | remove); | 3970 | remove); |
3971 | struct cgroup_subsys_state *css = event->css; | 3971 | struct cgroup_subsys_state *css = event->css; |
3972 | struct cgroup *cgrp = css->cgroup; | ||
3973 | 3972 | ||
3974 | remove_wait_queue(event->wqh, &event->wait); | 3973 | remove_wait_queue(event->wqh, &event->wait); |
3975 | 3974 | ||
@@ -3980,7 +3979,7 @@ static void cgroup_event_remove(struct work_struct *work) | |||
3980 | 3979 | ||
3981 | eventfd_ctx_put(event->eventfd); | 3980 | eventfd_ctx_put(event->eventfd); |
3982 | kfree(event); | 3981 | kfree(event); |
3983 | cgroup_dput(cgrp); | 3982 | css_put(css); |
3984 | } | 3983 | } |
3985 | 3984 | ||
3986 | /* | 3985 | /* |
@@ -4103,12 +4102,16 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *dummy_css, | |||
4103 | goto out_put_cfile; | 4102 | goto out_put_cfile; |
4104 | } | 4103 | } |
4105 | 4104 | ||
4106 | /* determine the css of @cfile and associate @event with it */ | 4105 | /* |
4106 | * Determine the css of @cfile and associate @event with it. | ||
4107 | * Remaining events are automatically removed on cgroup destruction | ||
4108 | * but the removal is asynchronous, so take an extra ref. | ||
4109 | */ | ||
4107 | rcu_read_lock(); | 4110 | rcu_read_lock(); |
4108 | 4111 | ||
4109 | ret = -EINVAL; | 4112 | ret = -EINVAL; |
4110 | event->css = cgroup_css(cgrp, event->cft->ss); | 4113 | event->css = cgroup_css(cgrp, event->cft->ss); |
4111 | if (event->css) | 4114 | if (event->css && css_tryget(event->css)) |
4112 | ret = 0; | 4115 | ret = 0; |
4113 | 4116 | ||
4114 | rcu_read_unlock(); | 4117 | rcu_read_unlock(); |
@@ -4122,28 +4125,21 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *dummy_css, | |||
4122 | cgrp_cfile = __d_cgrp(cfile->f_dentry->d_parent); | 4125 | cgrp_cfile = __d_cgrp(cfile->f_dentry->d_parent); |
4123 | if (cgrp_cfile != cgrp) { | 4126 | if (cgrp_cfile != cgrp) { |
4124 | ret = -EINVAL; | 4127 | ret = -EINVAL; |
4125 | goto out_put_cfile; | 4128 | goto out_put_css; |
4126 | } | 4129 | } |
4127 | 4130 | ||
4128 | if (!event->cft->register_event || !event->cft->unregister_event) { | 4131 | if (!event->cft->register_event || !event->cft->unregister_event) { |
4129 | ret = -EINVAL; | 4132 | ret = -EINVAL; |
4130 | goto out_put_cfile; | 4133 | goto out_put_css; |
4131 | } | 4134 | } |
4132 | 4135 | ||
4133 | ret = event->cft->register_event(event->css, event->cft, | 4136 | ret = event->cft->register_event(event->css, event->cft, |
4134 | event->eventfd, buffer); | 4137 | event->eventfd, buffer); |
4135 | if (ret) | 4138 | if (ret) |
4136 | goto out_put_cfile; | 4139 | goto out_put_css; |
4137 | 4140 | ||
4138 | efile->f_op->poll(efile, &event->pt); | 4141 | efile->f_op->poll(efile, &event->pt); |
4139 | 4142 | ||
4140 | /* | ||
4141 | * Events should be removed after rmdir of cgroup directory, but before | ||
4142 | * destroying subsystem state objects. Let's take reference to cgroup | ||
4143 | * directory dentry to do that. | ||
4144 | */ | ||
4145 | dget(cgrp->dentry); | ||
4146 | |||
4147 | spin_lock(&cgrp->event_list_lock); | 4143 | spin_lock(&cgrp->event_list_lock); |
4148 | list_add(&event->list, &cgrp->event_list); | 4144 | list_add(&event->list, &cgrp->event_list); |
4149 | spin_unlock(&cgrp->event_list_lock); | 4145 | spin_unlock(&cgrp->event_list_lock); |
@@ -4153,6 +4149,8 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *dummy_css, | |||
4153 | 4149 | ||
4154 | return 0; | 4150 | return 0; |
4155 | 4151 | ||
4152 | out_put_css: | ||
4153 | css_put(event->css); | ||
4156 | out_put_cfile: | 4154 | out_put_cfile: |
4157 | fput(cfile); | 4155 | fput(cfile); |
4158 | out_put_eventfd: | 4156 | out_put_eventfd: |