diff options
author | Ben Blum <bblum@andrew.cmu.edu> | 2011-11-02 16:38:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-02 19:06:59 -0400 |
commit | 33ef6b6984403a688189317ef46bb3caab3b70e0 (patch) | |
tree | 43dff6dd0150b34ce69b1d681c92659c9b20eb5c /kernel/cgroup.c | |
parent | 434a964daa14b9db083ce20404a4a2add54d037a (diff) |
cgroups: more safe tasklist locking in cgroup_attach_proc
Fix unstable tasklist locking in cgroup_attach_proc.
According to this thread - https://lkml.org/lkml/2011/7/27/243 - RCU is
not sufficient to guarantee the tasklist is stable w.r.t. de_thread and
exit. Taking tasklist_lock for reading, instead of rcu_read_lock, ensures
proper exclusion.
Signed-off-by: Ben Blum <bblum@andrew.cmu.edu>
Acked-by: Paul Menage <paul@paulmenage.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
Cc: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 6 |
1 files changed, 3 insertions, 3 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 453100a4159d..64b0e73402df 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -2027,7 +2027,7 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader) | |||
2027 | goto out_free_group_list; | 2027 | goto out_free_group_list; |
2028 | 2028 | ||
2029 | /* prevent changes to the threadgroup list while we take a snapshot. */ | 2029 | /* prevent changes to the threadgroup list while we take a snapshot. */ |
2030 | rcu_read_lock(); | 2030 | read_lock(&tasklist_lock); |
2031 | if (!thread_group_leader(leader)) { | 2031 | if (!thread_group_leader(leader)) { |
2032 | /* | 2032 | /* |
2033 | * a race with de_thread from another thread's exec() may strip | 2033 | * a race with de_thread from another thread's exec() may strip |
@@ -2036,7 +2036,7 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader) | |||
2036 | * throw this task away and try again (from cgroup_procs_write); | 2036 | * throw this task away and try again (from cgroup_procs_write); |
2037 | * this is "double-double-toil-and-trouble-check locking". | 2037 | * this is "double-double-toil-and-trouble-check locking". |
2038 | */ | 2038 | */ |
2039 | rcu_read_unlock(); | 2039 | read_unlock(&tasklist_lock); |
2040 | retval = -EAGAIN; | 2040 | retval = -EAGAIN; |
2041 | goto out_free_group_list; | 2041 | goto out_free_group_list; |
2042 | } | 2042 | } |
@@ -2057,7 +2057,7 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader) | |||
2057 | } while_each_thread(leader, tsk); | 2057 | } while_each_thread(leader, tsk); |
2058 | /* remember the number of threads in the array for later. */ | 2058 | /* remember the number of threads in the array for later. */ |
2059 | group_size = i; | 2059 | group_size = i; |
2060 | rcu_read_unlock(); | 2060 | read_unlock(&tasklist_lock); |
2061 | 2061 | ||
2062 | /* | 2062 | /* |
2063 | * step 1: check that we can legitimately attach to the cgroup. | 2063 | * step 1: check that we can legitimately attach to the cgroup. |