]> git.hungrycats.org Git - linux/commitdiff
Fix subtle fork() race that Ingo noticed.
authorLinus Torvalds <torvalds@home.osdl.org>
Thu, 8 Jan 2004 03:46:52 +0000 (19:46 -0800)
committerLinus Torvalds <torvalds@home.osdl.org>
Thu, 8 Jan 2004 03:46:52 +0000 (19:46 -0800)
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.

kernel/fork.c
kernel/sched.c

index 0603f230146b19a166330a834f392c7befa3ee93..8cea5daa08a03ba2a65521fa47c48a0f4891ed2f 100644 (file)
@@ -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)) {
index e6f2809808864233b3df78dae7e90acd196c7275..6f79281c39541a26b5028590ba4f5da71fecabc3 100644 (file)
@@ -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