diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2008-04-22 14:28:29 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2008-04-22 14:28:29 +1000 |
commit | 84e617547649db02e7569bd20ccc03b1ca6a60a0 (patch) | |
tree | 9ab06adc44a6eae79fe2145373a900bbd40c4f97 | |
parent | bbc8c3f79b6d75aa02f5b732713e6aea759cb839 (diff) | |
parent | 5638f21410ad48ee296589786fab2c90ae73beb3 (diff) |
Merge commit 'hrt/mm'
-rw-r--r-- | arch/ia64/kernel/time.c | 19 | ||||
-rw-r--r-- | arch/powerpc/kernel/time.c | 23 | ||||
-rw-r--r-- | arch/x86/kernel/vsyscall_64.c | 18 | ||||
-rw-r--r-- | include/linux/clocksource.h | 10 | ||||
-rw-r--r-- | kernel/time/timekeeping.c | 8 |
5 files changed, 62 insertions, 16 deletions
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index 48e15a51782f..efd64b666537 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -427,11 +427,22 @@ void update_vsyscall_tz(void) { } -void update_vsyscall(struct timespec *wall, struct clocksource *c) +/* update_vsyscall_lock/unlock: + * methods for timekeeping core to block vsyscalls during update + */ +void update_vsyscall_lock(unsigned long *flags) { - unsigned long flags; + write_seqlock_irqsave(&fsyscall_gtod_data.lock, *flags); +} - write_seqlock_irqsave(&fsyscall_gtod_data.lock, flags); +void update_vsyscall_unlock(unsigned long *flags) +{ + write_sequnlock_irqrestore(&fsyscall_gtod_data.lock, *flags); +} + +/* Assumes fsyscall_gtod_data.lock has been taken via update_vsyscall_lock() */ +void update_vsyscall(struct timespec *wall, struct clocksource *c) +{ /* copy fsyscall clock data */ fsyscall_gtod_data.clk_mask = c->mask; @@ -453,7 +464,5 @@ void update_vsyscall(struct timespec *wall, struct clocksource *c) fsyscall_gtod_data.monotonic_time.tv_nsec -= NSEC_PER_SEC; fsyscall_gtod_data.monotonic_time.tv_sec++; } - - write_sequnlock_irqrestore(&fsyscall_gtod_data.lock, flags); } diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 3b26fbd6bec9..c51d2f822f88 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -456,8 +456,6 @@ static inline void update_gtod(u64 new_tb_stamp, u64 new_stamp_xsec, vdso_data->tb_to_xs = new_tb_to_xs; vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec; vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec; - smp_wmb(); - ++(vdso_data->tb_update_count); } #ifdef CONFIG_SMP @@ -801,6 +799,23 @@ static cycle_t timebase_read(void) return (cycle_t)get_tb(); } +/* update_vsyscall_lock/unlock: + * methods for timekeeping core to block vsyscalls during update + */ +void update_vsyscall_lock(unsigned long *flags) +{ + /* Make userspace gettimeofday spin until we're done. */ + ++vdso_data->tb_update_count; + smp_mb(); +} + +void update_vsyscall_unlock(unsigned long *flags) +{ + smp_wmb(); + ++(vdso_data->tb_update_count); +} + +/* Assumes update_vsyscall_lock() has been called */ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock) { u64 t2x, stamp_xsec; @@ -808,10 +823,6 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock) if (clock != &clocksource_timebase) return; - /* Make userspace gettimeofday spin until we're done. */ - ++vdso_data->tb_update_count; - smp_mb(); - /* XXX this assumes clock->shift == 22 */ /* 4611686018 ~= 2^(20+64-22) / 1e9 */ t2x = (u64) clock->mult * 4611686018ULL; diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c index a1d817f7b3fc..bad19d0afced 100644 --- a/arch/x86/kernel/vsyscall_64.c +++ b/arch/x86/kernel/vsyscall_64.c @@ -70,11 +70,22 @@ void update_vsyscall_tz(void) write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags); } -void update_vsyscall(struct timespec *wall_time, struct clocksource *clock) +/* update_vsyscall_lock/unlock: + * methods for timekeeping core to block vsyscalls during update + */ +void update_vsyscall_lock(unsigned long *flags) { - unsigned long flags; + write_seqlock_irqsave(&vsyscall_gtod_data.lock, *flags); +} - write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags); +void update_vsyscall_unlock(unsigned long *flags) +{ + write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, *flags); +} + +/* Assumes vsyscall_gtod_data.lock has been taken via update_vsyscall_lock() */ +void update_vsyscall(struct timespec *wall_time, struct clocksource *clock) +{ /* copy vsyscall data */ vsyscall_gtod_data.clock.vread = clock->vread; vsyscall_gtod_data.clock.cycle_last = clock->cycle_last; @@ -84,7 +95,6 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock) vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec; vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec; vsyscall_gtod_data.wall_to_monotonic = wall_to_monotonic; - write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags); } /* RED-PEN may want to readd seq locking, but then the variable should be diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 35094479ca55..3677ef71ee54 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -222,9 +222,19 @@ extern void clocksource_change_rating(struct clocksource *cs, int rating); extern void clocksource_resume(void); #ifdef CONFIG_GENERIC_TIME_VSYSCALL +void update_vsyscall_lock(unsigned long *flags); +void update_vsyscall_unlock(unsigned long *flags); extern void update_vsyscall(struct timespec *ts, struct clocksource *c); extern void update_vsyscall_tz(void); #else +static inline void update_vsyscall_lock(unsigned long *flags) +{ +} + +static inline void update_vsyscall_unlock(unsigned long *flags) +{ +} + static inline void update_vsyscall(struct timespec *ts, struct clocksource *c) { } diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 2d6087c7cf98..05c7126709a8 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -129,7 +129,7 @@ EXPORT_SYMBOL(do_gettimeofday); */ int do_settimeofday(struct timespec *tv) { - unsigned long flags; + unsigned long flags, vflags; time_t wtm_sec, sec = tv->tv_sec; long wtm_nsec, nsec = tv->tv_nsec; @@ -137,6 +137,7 @@ int do_settimeofday(struct timespec *tv) return -EINVAL; write_seqlock_irqsave(&xtime_lock, flags); + update_vsyscall_lock(&vflags); nsec -= __get_nsec_offset(); @@ -152,6 +153,7 @@ int do_settimeofday(struct timespec *tv) update_vsyscall(&xtime, clock); + update_vsyscall_unlock(&vflags); write_sequnlock_irqrestore(&xtime_lock, flags); /* signal hrtimers about time change */ @@ -444,12 +446,15 @@ static void clocksource_adjust(s64 offset) */ void update_wall_time(void) { + unsigned long flags; cycle_t offset; /* Make sure we're fully resumed: */ if (unlikely(timekeeping_suspended)) return; + /* grab the vsyscall lock to block vsyscalls during update */ + update_vsyscall_lock(&flags); #ifdef CONFIG_GENERIC_TIME offset = (clocksource_read(clock) - clock->cycle_last) & clock->mask; #else @@ -489,6 +494,7 @@ void update_wall_time(void) /* check to see if there is a new clocksource to use */ change_clocksource(); update_vsyscall(&xtime, clock); + update_vsyscall_unlock(&flags); } /** |