aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cgroup_freezer.c
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2012-10-26 13:46:06 -0400
committerTejun Heo <tj@kernel.org>2012-10-26 17:27:49 -0400
commit5d8f72b55c275677865de670fa147ed318191d81 (patch)
tree58f4f571440f412861a232ed0c5753771e5a6e58 /kernel/cgroup_freezer.c
parentead5c473712eb26db792b18a4dc98fdb312883fe (diff)
freezer: change ptrace_stop/do_signal_stop to use freezable_schedule()
try_to_freeze_tasks() and cgroup_freezer rely on scheduler locks to ensure that a task doing STOPPED/TRACED -> RUNNING transition can't escape freezing. This mostly works, but ptrace_stop() does not necessarily call schedule(), it can change task->state back to RUNNING and check freezing() without any lock/barrier in between. We could add the necessary barrier, but this patch changes ptrace_stop() and do_signal_stop() to use freezable_schedule(). This fixes the race, freezer_count() and freezer_should_skip() carefully avoid the race. And this simplifies the code, try_to_freeze_tasks/update_if_frozen no longer need to use task_is_stopped_or_traced() checks with the non trivial assumptions. We can rely on the mechanism which was specially designed to mark the sleeping task as "frozen enough". v2: As Tejun pointed out, we can also change get_signal_to_deliver() and move try_to_freeze() up before 'relock' label. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'kernel/cgroup_freezer.c')
-rw-r--r--kernel/cgroup_freezer.c3
1 files changed, 1 insertions, 2 deletions
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c
index 8a92b0e52099..bedefd9a22df 100644
--- a/kernel/cgroup_freezer.c
+++ b/kernel/cgroup_freezer.c
@@ -198,8 +198,7 @@ static void update_if_frozen(struct cgroup *cgroup, struct freezer *freezer)
198 * completion. Consider it frozen in addition to 198 * completion. Consider it frozen in addition to
199 * the usual frozen condition. 199 * the usual frozen condition.
200 */ 200 */
201 if (!frozen(task) && !task_is_stopped_or_traced(task) && 201 if (!frozen(task) && !freezer_should_skip(task))
202 !freezer_should_skip(task))
203 goto notyet; 202 goto notyet;
204 } 203 }
205 } 204 }