xen-vtx-unstable
changeset 6026:b63577ff53a3
Fix xtime_lock handling to avoid deadlock in sched_clock().
Signed-off-by: Keir Fraser <keir@xensource.com>
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 =