diff options
-rw-r--r-- | arch/x86/include/asm/vgtod.h | 1 | ||||
-rw-r--r-- | arch/x86/kernel/vsyscall_64.c | 1 | ||||
-rw-r--r-- | arch/x86/vdso/vclock_gettime.c | 39 | ||||
-rw-r--r-- | include/linux/time.h | 4 | ||||
-rw-r--r-- | kernel/posix-timers.c | 35 | ||||
-rw-r--r-- | kernel/time/timekeeping.c | 21 |
6 files changed, 98 insertions, 3 deletions
diff --git a/arch/x86/include/asm/vgtod.h b/arch/x86/include/asm/vgtod.h index dc27a69e5d2a..3d61e204826f 100644 --- a/arch/x86/include/asm/vgtod.h +++ b/arch/x86/include/asm/vgtod.h | |||
@@ -21,6 +21,7 @@ struct vsyscall_gtod_data { | |||
21 | u32 shift; | 21 | u32 shift; |
22 | } clock; | 22 | } clock; |
23 | struct timespec wall_to_monotonic; | 23 | struct timespec wall_to_monotonic; |
24 | struct timespec wall_time_coarse; | ||
24 | }; | 25 | }; |
25 | extern struct vsyscall_gtod_data __vsyscall_gtod_data | 26 | extern struct vsyscall_gtod_data __vsyscall_gtod_data |
26 | __section_vsyscall_gtod_data; | 27 | __section_vsyscall_gtod_data; |
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c index 25ee06a80aad..cf53a78e2dcf 100644 --- a/arch/x86/kernel/vsyscall_64.c +++ b/arch/x86/kernel/vsyscall_64.c | |||
@@ -87,6 +87,7 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock) | |||
87 | vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec; | 87 | vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec; |
88 | vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec; | 88 | vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec; |
89 | vsyscall_gtod_data.wall_to_monotonic = wall_to_monotonic; | 89 | vsyscall_gtod_data.wall_to_monotonic = wall_to_monotonic; |
90 | vsyscall_gtod_data.wall_time_coarse = __current_kernel_time(); | ||
90 | write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags); | 91 | write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags); |
91 | } | 92 | } |
92 | 93 | ||
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c index 6a40b78b46aa..ee55754cc3c5 100644 --- a/arch/x86/vdso/vclock_gettime.c +++ b/arch/x86/vdso/vclock_gettime.c | |||
@@ -86,14 +86,47 @@ notrace static noinline int do_monotonic(struct timespec *ts) | |||
86 | return 0; | 86 | return 0; |
87 | } | 87 | } |
88 | 88 | ||
89 | notrace static noinline int do_realtime_coarse(struct timespec *ts) | ||
90 | { | ||
91 | unsigned long seq; | ||
92 | do { | ||
93 | seq = read_seqbegin(>od->lock); | ||
94 | ts->tv_sec = gtod->wall_time_coarse.tv_sec; | ||
95 | ts->tv_nsec = gtod->wall_time_coarse.tv_nsec; | ||
96 | } while (unlikely(read_seqretry(>od->lock, seq))); | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | notrace static noinline int do_monotonic_coarse(struct timespec *ts) | ||
101 | { | ||
102 | unsigned long seq, ns, secs; | ||
103 | do { | ||
104 | seq = read_seqbegin(>od->lock); | ||
105 | secs = gtod->wall_time_coarse.tv_sec; | ||
106 | ns = gtod->wall_time_coarse.tv_nsec; | ||
107 | secs += gtod->wall_to_monotonic.tv_sec; | ||
108 | ns += gtod->wall_to_monotonic.tv_nsec; | ||
109 | } while (unlikely(read_seqretry(>od->lock, seq))); | ||
110 | vset_normalized_timespec(ts, secs, ns); | ||
111 | return 0; | ||
112 | } | ||
113 | |||
89 | notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts) | 114 | notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts) |
90 | { | 115 | { |
91 | if (likely(gtod->sysctl_enabled && gtod->clock.vread)) | 116 | if (likely(gtod->sysctl_enabled)) |
92 | switch (clock) { | 117 | switch (clock) { |
93 | case CLOCK_REALTIME: | 118 | case CLOCK_REALTIME: |
94 | return do_realtime(ts); | 119 | if (likely(gtod->clock.vread)) |
120 | return do_realtime(ts); | ||
121 | break; | ||
95 | case CLOCK_MONOTONIC: | 122 | case CLOCK_MONOTONIC: |
96 | return do_monotonic(ts); | 123 | if (likely(gtod->clock.vread)) |
124 | return do_monotonic(ts); | ||
125 | break; | ||
126 | case CLOCK_REALTIME_COARSE: | ||
127 | return do_realtime_coarse(ts); | ||
128 | case CLOCK_MONOTONIC_COARSE: | ||
129 | return do_monotonic_coarse(ts); | ||
97 | } | 130 | } |
98 | return vdso_fallback_gettime(clock, ts); | 131 | return vdso_fallback_gettime(clock, ts); |
99 | } | 132 | } |
diff --git a/include/linux/time.h b/include/linux/time.h index f505988398e6..256232f7e5e6 100644 --- a/include/linux/time.h +++ b/include/linux/time.h | |||
@@ -110,6 +110,8 @@ extern int timekeeping_suspended; | |||
110 | 110 | ||
111 | unsigned long get_seconds(void); | 111 | unsigned long get_seconds(void); |
112 | struct timespec current_kernel_time(void); | 112 | struct timespec current_kernel_time(void); |
113 | struct timespec __current_kernel_time(void); /* does not hold xtime_lock */ | ||
114 | struct timespec get_monotonic_coarse(void); | ||
113 | 115 | ||
114 | #define CURRENT_TIME (current_kernel_time()) | 116 | #define CURRENT_TIME (current_kernel_time()) |
115 | #define CURRENT_TIME_SEC ((struct timespec) { get_seconds(), 0 }) | 117 | #define CURRENT_TIME_SEC ((struct timespec) { get_seconds(), 0 }) |
@@ -243,6 +245,8 @@ struct itimerval { | |||
243 | #define CLOCK_PROCESS_CPUTIME_ID 2 | 245 | #define CLOCK_PROCESS_CPUTIME_ID 2 |
244 | #define CLOCK_THREAD_CPUTIME_ID 3 | 246 | #define CLOCK_THREAD_CPUTIME_ID 3 |
245 | #define CLOCK_MONOTONIC_RAW 4 | 247 | #define CLOCK_MONOTONIC_RAW 4 |
248 | #define CLOCK_REALTIME_COARSE 5 | ||
249 | #define CLOCK_MONOTONIC_COARSE 6 | ||
246 | 250 | ||
247 | /* | 251 | /* |
248 | * The IDs of various hardware clocks: | 252 | * The IDs of various hardware clocks: |
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index d089d052c4a9..495440779ce3 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c | |||
@@ -242,6 +242,25 @@ static int posix_get_monotonic_raw(clockid_t which_clock, struct timespec *tp) | |||
242 | return 0; | 242 | return 0; |
243 | } | 243 | } |
244 | 244 | ||
245 | |||
246 | static int posix_get_realtime_coarse(clockid_t which_clock, struct timespec *tp) | ||
247 | { | ||
248 | *tp = current_kernel_time(); | ||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static int posix_get_monotonic_coarse(clockid_t which_clock, | ||
253 | struct timespec *tp) | ||
254 | { | ||
255 | *tp = get_monotonic_coarse(); | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | int posix_get_coarse_res(const clockid_t which_clock, struct timespec *tp) | ||
260 | { | ||
261 | *tp = ktime_to_timespec(KTIME_LOW_RES); | ||
262 | return 0; | ||
263 | } | ||
245 | /* | 264 | /* |
246 | * Initialize everything, well, just everything in Posix clocks/timers ;) | 265 | * Initialize everything, well, just everything in Posix clocks/timers ;) |
247 | */ | 266 | */ |
@@ -262,10 +281,26 @@ static __init int init_posix_timers(void) | |||
262 | .timer_create = no_timer_create, | 281 | .timer_create = no_timer_create, |
263 | .nsleep = no_nsleep, | 282 | .nsleep = no_nsleep, |
264 | }; | 283 | }; |
284 | struct k_clock clock_realtime_coarse = { | ||
285 | .clock_getres = posix_get_coarse_res, | ||
286 | .clock_get = posix_get_realtime_coarse, | ||
287 | .clock_set = do_posix_clock_nosettime, | ||
288 | .timer_create = no_timer_create, | ||
289 | .nsleep = no_nsleep, | ||
290 | }; | ||
291 | struct k_clock clock_monotonic_coarse = { | ||
292 | .clock_getres = posix_get_coarse_res, | ||
293 | .clock_get = posix_get_monotonic_coarse, | ||
294 | .clock_set = do_posix_clock_nosettime, | ||
295 | .timer_create = no_timer_create, | ||
296 | .nsleep = no_nsleep, | ||
297 | }; | ||
265 | 298 | ||
266 | register_posix_clock(CLOCK_REALTIME, &clock_realtime); | 299 | register_posix_clock(CLOCK_REALTIME, &clock_realtime); |
267 | register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic); | 300 | register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic); |
268 | register_posix_clock(CLOCK_MONOTONIC_RAW, &clock_monotonic_raw); | 301 | register_posix_clock(CLOCK_MONOTONIC_RAW, &clock_monotonic_raw); |
302 | register_posix_clock(CLOCK_REALTIME_COARSE, &clock_realtime_coarse); | ||
303 | register_posix_clock(CLOCK_MONOTONIC_COARSE, &clock_monotonic_coarse); | ||
269 | 304 | ||
270 | posix_timers_cache = kmem_cache_create("posix_timers_cache", | 305 | posix_timers_cache = kmem_cache_create("posix_timers_cache", |
271 | sizeof (struct k_itimer), 0, SLAB_PANIC, | 306 | sizeof (struct k_itimer), 0, SLAB_PANIC, |
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 15e06defca55..03cbeb34d141 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -847,6 +847,10 @@ unsigned long get_seconds(void) | |||
847 | } | 847 | } |
848 | EXPORT_SYMBOL(get_seconds); | 848 | EXPORT_SYMBOL(get_seconds); |
849 | 849 | ||
850 | struct timespec __current_kernel_time(void) | ||
851 | { | ||
852 | return xtime_cache; | ||
853 | } | ||
850 | 854 | ||
851 | struct timespec current_kernel_time(void) | 855 | struct timespec current_kernel_time(void) |
852 | { | 856 | { |
@@ -862,3 +866,20 @@ struct timespec current_kernel_time(void) | |||
862 | return now; | 866 | return now; |
863 | } | 867 | } |
864 | EXPORT_SYMBOL(current_kernel_time); | 868 | EXPORT_SYMBOL(current_kernel_time); |
869 | |||
870 | struct timespec get_monotonic_coarse(void) | ||
871 | { | ||
872 | struct timespec now, mono; | ||
873 | unsigned long seq; | ||
874 | |||
875 | do { | ||
876 | seq = read_seqbegin(&xtime_lock); | ||
877 | |||
878 | now = xtime_cache; | ||
879 | mono = wall_to_monotonic; | ||
880 | } while (read_seqretry(&xtime_lock, seq)); | ||
881 | |||
882 | set_normalized_timespec(&now, now.tv_sec + mono.tv_sec, | ||
883 | now.tv_nsec + mono.tv_nsec); | ||
884 | return now; | ||
885 | } | ||