Commit f7a1132c authored by Linus Torvalds's avatar Linus Torvalds

Fix subtle fork() race that Ingo noticed.

We must not mark the process TASK_STOPPED early, because
that might allow a signal to wake it up before we actually
got to the "wake_up_forked_process()" state. Total confusion
would happen.

Make wake_up_forked_process() verify the new world order.
parent f6fd6a01
......@@ -918,7 +918,14 @@ struct task_struct *copy_process(unsigned long clone_flags,
p->thread_info->preempt_count = 1;
#endif
p->did_exec = 0;
p->state = TASK_UNINTERRUPTIBLE;
/*
* We mark the process as running here, but have not actually
* inserted it onto the runqueue yet. This guarantees that
* nobody will actually run it, and a signal or other external
* event cannot wake it up and insert it on the runqueue either.
*/
p->state = TASK_RUNNING;
copy_flags(clone_flags, p);
if (clone_flags & CLONE_IDLETASK)
......@@ -1209,9 +1216,10 @@ long do_fork(unsigned long clone_flags,
set_tsk_thread_flag(p, TIF_SIGPENDING);
}
p->state = TASK_STOPPED;
if (!(clone_flags & CLONE_STOPPED))
wake_up_forked_process(p); /* do this last */
else
p->state = TASK_STOPPED;
++total_forks;
if (unlikely (trace)) {
......
......@@ -684,7 +684,8 @@ void wake_up_forked_process(task_t * p)
unsigned long flags;
runqueue_t *rq = task_rq_lock(current, &flags);
p->state = TASK_RUNNING;
BUG_ON(p->state != TASK_RUNNING);
/*
* We decrease the sleep average of forking parents
* and children as well, to keep max-interactive tasks
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment