summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2008-04-22 14:28:29 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2008-04-22 14:28:29 +1000
commit84e617547649db02e7569bd20ccc03b1ca6a60a0 (patch)
tree9ab06adc44a6eae79fe2145373a900bbd40c4f97
parentbbc8c3f79b6d75aa02f5b732713e6aea759cb839 (diff)
parent5638f21410ad48ee296589786fab2c90ae73beb3 (diff)
Merge commit 'hrt/mm'
-rw-r--r--arch/ia64/kernel/time.c19
-rw-r--r--arch/powerpc/kernel/time.c23
-rw-r--r--arch/x86/kernel/vsyscall_64.c18
-rw-r--r--include/linux/clocksource.h10
-rw-r--r--kernel/time/timekeeping.c8
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);
}
/**