From: Ingo Molnar <mingo@elte.hu>

Rusty noticed that we update the parent ->avg_sleep without holding the
runqueue lock. Also the code needed cleanups.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/kernel/sched.c |   24 +++++++++++++++---------
 1 files changed, 15 insertions(+), 9 deletions(-)

diff -puN kernel/sched.c~sched-new-task-fix kernel/sched.c
--- 25/kernel/sched.c~sched-new-task-fix	Tue Aug 17 15:03:25 2004
+++ 25-akpm/kernel/sched.c	Tue Aug 17 15:03:25 2004
@@ -1342,7 +1342,7 @@ void fastcall wake_up_new_task(task_t * 
 {
 	unsigned long flags;
 	int this_cpu, cpu;
-	runqueue_t *rq;
+	runqueue_t *rq, *this_rq;
 
 	rq = task_rq_lock(p, &flags);
 	cpu = task_cpu(p);
@@ -1384,8 +1384,15 @@ void fastcall wake_up_new_task(task_t * 
 		} else
 			/* Run child last */
 			__activate_task(p, rq);
+		/*
+		 * We skip the following code due to cpu == this_cpu
+	 	 *
+		 *   task_rq_unlock(rq, &flags);
+		 *   this_rq = task_rq_lock(current, &flags);
+		 */
+		this_rq = rq;
 	} else {
-		runqueue_t *this_rq = cpu_rq(this_cpu);
+		this_rq = cpu_rq(this_cpu);
 
 		/*
 		 * Not the local CPU - must adjust timestamp. This should
@@ -1397,18 +1404,17 @@ void fastcall wake_up_new_task(task_t * 
 		if (TASK_PREEMPTS_CURR(p, rq))
 			resched_task(rq->curr);
 
-		current->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(current) *
-			PARENT_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS);
 		schedstat_inc(rq, wunt_moved);
-	}
-
-	if (unlikely(cpu != this_cpu)) {
+		/*
+		 * Parent and child are on different CPUs, now get the
+		 * parent runqueue to update the parent's ->sleep_avg:
+		 */
 		task_rq_unlock(rq, &flags);
-		rq = task_rq_lock(current, &flags);
+		this_rq = task_rq_lock(current, &flags);
 	}
 	current->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(current) *
 		PARENT_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS);
-	task_rq_unlock(rq, &flags);
+	task_rq_unlock(this_rq, &flags);
 }
 
 /*
_