aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Breeds <tony@bakeyournoodle.com>2007-10-18 06:04:57 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-18 17:37:20 -0400
commit2c6221483169ddd4c04797cd7296ed4fe52fcdd7 (patch)
tree1db73f0bf60b036abe995350637a9a3e916c0ec2
parent6212e3a388fdda3f19fa660ef5a30edf54d1dcfd (diff)
Fix discrepancy between VDSO based gettimeofday() and sys_gettimeofday().
On platforms that copy sys_tz into the vdso (currently only x86_64, soon to include powerpc), it is possible for the vdso to get out of sync if a user calls (admittedly unusual) settimeofday(NULL, ptr). This patch adds a hook for architectures that set CONFIG_GENERIC_TIME_VSYSCALL to ensure when sys_tz is updated they can also updatee their copy in the vdso. Signed-off-by: Tony Breeds <tony@bakeyournoodle.com> Cc: Andi Kleen <ak@suse.de> Cc: Tony Luck <tony.luck@intel.com> Acked-by: John Stultz <johnstul@us.ibm.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/ia64/kernel/time.c5
-rw-r--r--arch/x86/kernel/vsyscall_64.c11
-rw-r--r--include/linux/clocksource.h5
-rw-r--r--kernel/time.c2
4 files changed, 22 insertions, 1 deletions
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 98cfc90cab1d..2bb84214e5f1 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -371,6 +371,11 @@ ia64_setup_printk_clock(void)
371 ia64_printk_clock = ia64_itc_printk_clock; 371 ia64_printk_clock = ia64_itc_printk_clock;
372} 372}
373 373
374/* IA64 doesn't cache the timezone */
375void update_vsyscall_tz(void)
376{
377}
378
374void update_vsyscall(struct timespec *wall, struct clocksource *c) 379void update_vsyscall(struct timespec *wall, struct clocksource *c)
375{ 380{
376 unsigned long flags; 381 unsigned long flags;
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c
index 8a67e282cb5e..f24e8acdec91 100644
--- a/arch/x86/kernel/vsyscall_64.c
+++ b/arch/x86/kernel/vsyscall_64.c
@@ -64,6 +64,16 @@ struct vsyscall_gtod_data __vsyscall_gtod_data __section_vsyscall_gtod_data =
64 .sysctl_enabled = 1, 64 .sysctl_enabled = 1,
65}; 65};
66 66
67void update_vsyscall_tz(void)
68{
69 unsigned long flags;
70
71 write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags);
72 /* sys_tz has changed */
73 vsyscall_gtod_data.sys_tz = sys_tz;
74 write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
75}
76
67void update_vsyscall(struct timespec *wall_time, struct clocksource *clock) 77void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
68{ 78{
69 unsigned long flags; 79 unsigned long flags;
@@ -77,7 +87,6 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
77 vsyscall_gtod_data.clock.shift = clock->shift; 87 vsyscall_gtod_data.clock.shift = clock->shift;
78 vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec; 88 vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec;
79 vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec; 89 vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
80 vsyscall_gtod_data.sys_tz = sys_tz;
81 vsyscall_gtod_data.wall_to_monotonic = wall_to_monotonic; 90 vsyscall_gtod_data.wall_to_monotonic = wall_to_monotonic;
82 write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags); 91 write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
83} 92}
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 16ea3374dddf..107787aacb64 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -221,10 +221,15 @@ extern void clocksource_resume(void);
221 221
222#ifdef CONFIG_GENERIC_TIME_VSYSCALL 222#ifdef CONFIG_GENERIC_TIME_VSYSCALL
223extern void update_vsyscall(struct timespec *ts, struct clocksource *c); 223extern void update_vsyscall(struct timespec *ts, struct clocksource *c);
224extern void update_vsyscall_tz(void);
224#else 225#else
225static inline void update_vsyscall(struct timespec *ts, struct clocksource *c) 226static inline void update_vsyscall(struct timespec *ts, struct clocksource *c)
226{ 227{
227} 228}
229
230static inline void update_vsyscall_tz(void)
231{
232}
228#endif 233#endif
229 234
230#endif /* _LINUX_CLOCKSOURCE_H */ 235#endif /* _LINUX_CLOCKSOURCE_H */
diff --git a/kernel/time.c b/kernel/time.c
index 2d5b6a682138..d9725bdcd045 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -30,6 +30,7 @@
30#include <linux/module.h> 30#include <linux/module.h>
31#include <linux/timex.h> 31#include <linux/timex.h>
32#include <linux/capability.h> 32#include <linux/capability.h>
33#include <linux/clocksource.h>
33#include <linux/errno.h> 34#include <linux/errno.h>
34#include <linux/syscalls.h> 35#include <linux/syscalls.h>
35#include <linux/security.h> 36#include <linux/security.h>
@@ -158,6 +159,7 @@ int do_sys_settimeofday(struct timespec *tv, struct timezone *tz)
158 if (tz) { 159 if (tz) {
159 /* SMP safe, global irq locking makes it work. */ 160 /* SMP safe, global irq locking makes it work. */
160 sys_tz = *tz; 161 sys_tz = *tz;
162 update_vsyscall_tz();
161 if (firsttime) { 163 if (firsttime) {
162 firsttime = 0; 164 firsttime = 0;
163 if (!tv) 165 if (!tv)