diff options
Diffstat (limited to 'arch/x86/vdso/vclock_gettime.c')
-rw-r--r-- | arch/x86/vdso/vclock_gettime.c | 74 |
1 files changed, 53 insertions, 21 deletions
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c index ee55754cc3c5..a724905fdae7 100644 --- a/arch/x86/vdso/vclock_gettime.c +++ b/arch/x86/vdso/vclock_gettime.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Copyright 2006 Andi Kleen, SUSE Labs. | 2 | * Copyright 2006 Andi Kleen, SUSE Labs. |
3 | * Subject to the GNU Public License, v.2 | 3 | * Subject to the GNU Public License, v.2 |
4 | * | 4 | * |
5 | * Fast user context implementation of clock_gettime and gettimeofday. | 5 | * Fast user context implementation of clock_gettime, gettimeofday, and time. |
6 | * | 6 | * |
7 | * The code should have no internal unresolved relocations. | 7 | * The code should have no internal unresolved relocations. |
8 | * Check with readelf after changing. | 8 | * Check with readelf after changing. |
@@ -22,9 +22,8 @@ | |||
22 | #include <asm/hpet.h> | 22 | #include <asm/hpet.h> |
23 | #include <asm/unistd.h> | 23 | #include <asm/unistd.h> |
24 | #include <asm/io.h> | 24 | #include <asm/io.h> |
25 | #include "vextern.h" | ||
26 | 25 | ||
27 | #define gtod vdso_vsyscall_gtod_data | 26 | #define gtod (&VVAR(vsyscall_gtod_data)) |
28 | 27 | ||
29 | notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) | 28 | notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) |
30 | { | 29 | { |
@@ -56,22 +55,6 @@ notrace static noinline int do_realtime(struct timespec *ts) | |||
56 | return 0; | 55 | return 0; |
57 | } | 56 | } |
58 | 57 | ||
59 | /* Copy of the version in kernel/time.c which we cannot directly access */ | ||
60 | notrace static void | ||
61 | vset_normalized_timespec(struct timespec *ts, long sec, long nsec) | ||
62 | { | ||
63 | while (nsec >= NSEC_PER_SEC) { | ||
64 | nsec -= NSEC_PER_SEC; | ||
65 | ++sec; | ||
66 | } | ||
67 | while (nsec < 0) { | ||
68 | nsec += NSEC_PER_SEC; | ||
69 | --sec; | ||
70 | } | ||
71 | ts->tv_sec = sec; | ||
72 | ts->tv_nsec = nsec; | ||
73 | } | ||
74 | |||
75 | notrace static noinline int do_monotonic(struct timespec *ts) | 58 | notrace static noinline int do_monotonic(struct timespec *ts) |
76 | { | 59 | { |
77 | unsigned long seq, ns, secs; | 60 | unsigned long seq, ns, secs; |
@@ -82,7 +65,17 @@ notrace static noinline int do_monotonic(struct timespec *ts) | |||
82 | secs += gtod->wall_to_monotonic.tv_sec; | 65 | secs += gtod->wall_to_monotonic.tv_sec; |
83 | ns += gtod->wall_to_monotonic.tv_nsec; | 66 | ns += gtod->wall_to_monotonic.tv_nsec; |
84 | } while (unlikely(read_seqretry(>od->lock, seq))); | 67 | } while (unlikely(read_seqretry(>od->lock, seq))); |
85 | vset_normalized_timespec(ts, secs, ns); | 68 | |
69 | /* wall_time_nsec, vgetns(), and wall_to_monotonic.tv_nsec | ||
70 | * are all guaranteed to be nonnegative. | ||
71 | */ | ||
72 | while (ns >= NSEC_PER_SEC) { | ||
73 | ns -= NSEC_PER_SEC; | ||
74 | ++secs; | ||
75 | } | ||
76 | ts->tv_sec = secs; | ||
77 | ts->tv_nsec = ns; | ||
78 | |||
86 | return 0; | 79 | return 0; |
87 | } | 80 | } |
88 | 81 | ||
@@ -107,7 +100,17 @@ notrace static noinline int do_monotonic_coarse(struct timespec *ts) | |||
107 | secs += gtod->wall_to_monotonic.tv_sec; | 100 | secs += gtod->wall_to_monotonic.tv_sec; |
108 | ns += gtod->wall_to_monotonic.tv_nsec; | 101 | ns += gtod->wall_to_monotonic.tv_nsec; |
109 | } while (unlikely(read_seqretry(>od->lock, seq))); | 102 | } while (unlikely(read_seqretry(>od->lock, seq))); |
110 | vset_normalized_timespec(ts, secs, ns); | 103 | |
104 | /* wall_time_nsec and wall_to_monotonic.tv_nsec are | ||
105 | * guaranteed to be between 0 and NSEC_PER_SEC. | ||
106 | */ | ||
107 | if (ns >= NSEC_PER_SEC) { | ||
108 | ns -= NSEC_PER_SEC; | ||
109 | ++secs; | ||
110 | } | ||
111 | ts->tv_sec = secs; | ||
112 | ts->tv_nsec = ns; | ||
113 | |||
111 | return 0; | 114 | return 0; |
112 | } | 115 | } |
113 | 116 | ||
@@ -157,3 +160,32 @@ notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) | |||
157 | } | 160 | } |
158 | int gettimeofday(struct timeval *, struct timezone *) | 161 | int gettimeofday(struct timeval *, struct timezone *) |
159 | __attribute__((weak, alias("__vdso_gettimeofday"))); | 162 | __attribute__((weak, alias("__vdso_gettimeofday"))); |
163 | |||
164 | /* This will break when the xtime seconds get inaccurate, but that is | ||
165 | * unlikely */ | ||
166 | |||
167 | static __always_inline long time_syscall(long *t) | ||
168 | { | ||
169 | long secs; | ||
170 | asm volatile("syscall" | ||
171 | : "=a" (secs) | ||
172 | : "0" (__NR_time), "D" (t) : "cc", "r11", "cx", "memory"); | ||
173 | return secs; | ||
174 | } | ||
175 | |||
176 | notrace time_t __vdso_time(time_t *t) | ||
177 | { | ||
178 | time_t result; | ||
179 | |||
180 | if (unlikely(!VVAR(vsyscall_gtod_data).sysctl_enabled)) | ||
181 | return time_syscall(t); | ||
182 | |||
183 | /* This is atomic on x86_64 so we don't need any locks. */ | ||
184 | result = ACCESS_ONCE(VVAR(vsyscall_gtod_data).wall_time_sec); | ||
185 | |||
186 | if (t) | ||
187 | *t = result; | ||
188 | return result; | ||
189 | } | ||
190 | int time(time_t *t) | ||
191 | __attribute__((weak, alias("__vdso_time"))); | ||