From: Ingo Molnar <mingo@elte.hu>

timer_interrupt does write_seqlock(&xtime_lock), and sched_clock() is
called inside timer_interrupt().  So sched_clock() cannot call
get_jiffies_64(), because that does read_seqretry(&xtime_lock).


The easy fix is below.  Since this only affects 1) non-TSC-sync 32-bit
systems, and since a once-every-400 days overflow will get the
interactivity of 1-2 tasks wrong, this is not a big thing.

To get cleanly out of the recursion we'd have to add a separate callback
from the TIMER_SOFTIRQ context, that updates rq->timestamp_last_tick and
does nothing else.  We dont want to move the rest of scheduler_tick() to
softirq context because the timer-IRQ is much more precise - softirqs can
get delayed.  So we've got to live with this small grossness.

Yet another solution would be to define a separate sched_clock_timer()
function, which an arch could separately fill in if it needs to.  (the
default would be to make sched_clock == sched_clock_timer) This way x86
could use the jiffies_64 value directly in sched_clock_timer(), and could
do the get_jiffies_64() thing in sched_clock().



 arch/i386/kernel/timers/timer_tsc.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletion(-)

diff -puN arch/i386/kernel/timers/timer_tsc.c~sched_clock-2.6.0-A1-deadlock-fix arch/i386/kernel/timers/timer_tsc.c
--- 25/arch/i386/kernel/timers/timer_tsc.c~sched_clock-2.6.0-A1-deadlock-fix	2003-12-30 00:45:09.000000000 -0800
+++ 25-akpm/arch/i386/kernel/timers/timer_tsc.c	2003-12-30 00:45:09.000000000 -0800
@@ -140,7 +140,8 @@ unsigned long long sched_clock(void)
 #ifndef CONFIG_NUMA
 	if (!use_tsc)
 #endif
-		return (unsigned long long)get_jiffies_64() * (1000000000 / HZ);
+		/* jiffies might overflow but this is not a big deal here */
+		return (unsigned long long)jiffies * (1000000000 / HZ);
 
 	/* Read the Time Stamp Counter */
 	rdtscll(this_offset);

_