ia64/xen-unstable

changeset 6041:b63577ff53a3

Fix xtime_lock handling to avoid deadlock in sched_clock().
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Fri Aug 05 14:57:43 2005 +0000 (2005-08-05)
parents 5a33233a608e
children 69b7c9c3a9fd
files linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c
line diff
     1.1 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c	Fri Aug 05 09:53:04 2005 +0000
     1.2 +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c	Fri Aug 05 14:57:43 2005 +0000
     1.3 @@ -233,6 +233,10 @@ static void update_wallclock(void)
     1.4  	time_t wtm_sec, xtime_sec;
     1.5  	u64 tmp, usec;
     1.6  
     1.7 +	if ((shadow_tv.tv_sec == s->wc_sec) &&
     1.8 +	    (shadow_tv.tv_usec == s->wc_usec))
     1.9 +		return;
    1.10 +
    1.11  	shadow_tv.tv_sec  = s->wc_sec;
    1.12  	shadow_tv.tv_usec = s->wc_usec;
    1.13  
    1.14 @@ -263,9 +267,9 @@ static void update_wallclock(void)
    1.15  
    1.16  /*
    1.17   * Reads a consistent set of time-base values from Xen, into a shadow data
    1.18 - * area. Must be called with the xtime_lock held for writing.
    1.19 + * area.
    1.20   */
    1.21 -static void __get_time_values_from_xen(void)
    1.22 +static void get_time_values_from_xen(void)
    1.23  {
    1.24  	shared_info_t           *s = HYPERVISOR_shared_info;
    1.25  	struct vcpu_time_info   *src;
    1.26 @@ -286,10 +290,6 @@ static void __get_time_values_from_xen(v
    1.27  	while (dst->version != src->time_version1);
    1.28  
    1.29  	dst->tsc_to_usec_mul = dst->tsc_to_nsec_mul / 1000;
    1.30 -
    1.31 -	if ((shadow_tv.tv_sec != s->wc_sec) ||
    1.32 -	    (shadow_tv.tv_usec != s->wc_usec))
    1.33 -		update_wallclock();
    1.34  }
    1.35  
    1.36  static inline int time_values_up_to_date(int cpu)
    1.37 @@ -341,10 +341,10 @@ void do_gettimeofday(struct timeval *tv)
    1.38  	unsigned long seq;
    1.39  	unsigned long usec, sec;
    1.40  	unsigned long max_ntp_tick;
    1.41 -	unsigned long flags;
    1.42  	s64 nsec;
    1.43  	unsigned int cpu;
    1.44  	struct shadow_time_info *shadow;
    1.45 +	u32 local_time_version;
    1.46  
    1.47  	cpu = get_cpu();
    1.48  	shadow = &per_cpu(shadow_time, cpu);
    1.49 @@ -352,6 +352,7 @@ void do_gettimeofday(struct timeval *tv)
    1.50  	do {
    1.51  		unsigned long lost;
    1.52  
    1.53 +		local_time_version = shadow->version;
    1.54  		seq = read_seqbegin(&xtime_lock);
    1.55  
    1.56  		usec = get_usec_offset(shadow);
    1.57 @@ -387,12 +388,11 @@ void do_gettimeofday(struct timeval *tv)
    1.58  			 * overflowed). Detect that and recalculate
    1.59  			 * with fresh values.
    1.60  			 */
    1.61 -			write_seqlock_irqsave(&xtime_lock, flags);
    1.62 -			__get_time_values_from_xen();
    1.63 -			write_sequnlock_irqrestore(&xtime_lock, flags);
    1.64 +			get_time_values_from_xen();
    1.65  			continue;
    1.66  		}
    1.67 -	} while (read_seqretry(&xtime_lock, seq));
    1.68 +	} while (read_seqretry(&xtime_lock, seq) ||
    1.69 +		 (local_time_version != shadow->version));
    1.70  
    1.71  	put_cpu();
    1.72  
    1.73 @@ -435,7 +435,7 @@ int do_settimeofday(struct timespec *tv)
    1.74   again:
    1.75  	nsec = (s64)tv->tv_nsec - (s64)get_nsec_offset(shadow);
    1.76  	if (unlikely(!time_values_up_to_date(cpu))) {
    1.77 -		__get_time_values_from_xen();
    1.78 +		get_time_values_from_xen();
    1.79  		goto again;
    1.80  	}
    1.81  
    1.82 @@ -517,21 +517,21 @@ unsigned long long monotonic_clock(void)
    1.83  {
    1.84  	int cpu = get_cpu();
    1.85  	struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu);
    1.86 -	s64 off;
    1.87 -	unsigned long flags;
    1.88 -	
    1.89 -	for ( ; ; ) {
    1.90 -		off = get_nsec_offset(shadow);
    1.91 -		if (time_values_up_to_date(cpu))
    1.92 -			break;
    1.93 -		write_seqlock_irqsave(&xtime_lock, flags);
    1.94 -		__get_time_values_from_xen();
    1.95 -		write_sequnlock_irqrestore(&xtime_lock, flags);
    1.96 -	}
    1.97 +	u64 time;
    1.98 +	u32 local_time_version;
    1.99 +
   1.100 +	do {
   1.101 +		local_time_version = shadow->version;
   1.102 +		smp_rmb();
   1.103 +		time = shadow->system_timestamp + get_nsec_offset(shadow);
   1.104 +		if (!time_values_up_to_date(cpu))
   1.105 +			get_time_values_from_xen();
   1.106 +		smp_rmb();
   1.107 +	} while (local_time_version != shadow->version);
   1.108  
   1.109  	put_cpu();
   1.110  
   1.111 -	return shadow->system_timestamp + off;
   1.112 +	return time;
   1.113  }
   1.114  EXPORT_SYMBOL(monotonic_clock);
   1.115  
   1.116 @@ -565,7 +565,7 @@ static inline void do_timer_interrupt(in
   1.117  	struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu);
   1.118  
   1.119  	do {
   1.120 -		__get_time_values_from_xen();
   1.121 +		get_time_values_from_xen();
   1.122  
   1.123  		delta = delta_cpu = 
   1.124  			shadow->system_timestamp + get_nsec_offset(shadow);
   1.125 @@ -602,6 +602,8 @@ static inline void do_timer_interrupt(in
   1.126  		update_process_times(user_mode(regs));
   1.127  		profile_tick(CPU_PROFILING, regs);
   1.128  	}
   1.129 +
   1.130 +	update_wallclock();
   1.131  }
   1.132  
   1.133  /*
   1.134 @@ -788,7 +790,8 @@ void __init time_init(void)
   1.135  		return;
   1.136  	}
   1.137  #endif
   1.138 -	__get_time_values_from_xen();
   1.139 +	get_time_values_from_xen();
   1.140 +	update_wallclock();
   1.141  	xtime.tv_sec = shadow_tv.tv_sec;
   1.142  	xtime.tv_nsec = shadow_tv.tv_usec * NSEC_PER_USEC;
   1.143  	set_normalized_timespec(&wall_to_monotonic,
   1.144 @@ -872,7 +875,8 @@ void time_resume(void)
   1.145  	init_cpu_khz();
   1.146  
   1.147  	/* Get timebases for new environment. */ 
   1.148 -	__get_time_values_from_xen();
   1.149 +	get_time_values_from_xen();
   1.150 +	update_wallclock();
   1.151  
   1.152  	/* Reset our own concept of passage of system time. */
   1.153  	processed_system_time =