aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cgroup.c
diff options
context:
space:
mode:
authorSalman Qazi <sqazi@google.com>2012-06-06 21:51:35 -0400
committerTejun Heo <tj@kernel.org>2012-06-06 21:51:35 -0400
commit967db0ea65b0bf8507a7643ac8f296c4f2c0a834 (patch)
tree143a9493c9a81db130b313c0c46d87a909485541 /kernel/cgroup.c
parent71fae7e714749a52cb8be777ec014f82e8a747f4 (diff)
cgroup: make sure that decisions in __css_put are atomic
__css_put is using atomic_dec on the ref count, and then looking at the ref count to make decisions. This is prone to races, as someone else may decrement ref count between our decrement and our decision. Instead, we should base our decisions on the value that we decremented the ref count to. (This results in an actual race on Google's kernel which I haven't been able to reproduce on the upstream kernel. Having said that, it's still incorrect by inspection). Signed-off-by: Salman Qazi <sqazi@google.com> Acked-by: Li Zefan <lizefan@huawei.com> Signed-off-by: Tejun Heo <tj@kernel.org> Cc: stable@vger.kernel.org
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r--kernel/cgroup.c3
1 files changed, 1 insertions, 2 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 72fcd3069a90..ceeafe874b3f 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -4984,8 +4984,7 @@ void __css_put(struct cgroup_subsys_state *css)
4984 struct cgroup *cgrp = css->cgroup; 4984 struct cgroup *cgrp = css->cgroup;
4985 4985
4986 rcu_read_lock(); 4986 rcu_read_lock();
4987 atomic_dec(&css->refcnt); 4987 switch (atomic_dec_return(&css->refcnt)) {
4988 switch (css_refcnt(css)) {
4989 case 1: 4988 case 1:
4990 if (notify_on_release(cgrp)) { 4989 if (notify_on_release(cgrp)) {
4991 set_bit(CGRP_RELEASABLE, &cgrp->flags); 4990 set_bit(CGRP_RELEASABLE, &cgrp->flags);