aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86_64/kernel/vsyscall.c53
1 files changed, 36 insertions, 17 deletions
diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
index ba330f870679..dc32cef96195 100644
--- a/arch/x86_64/kernel/vsyscall.c
+++ b/arch/x86_64/kernel/vsyscall.c
@@ -51,13 +51,28 @@
51 asm("" : "=r" (v) : "0" (x)); \ 51 asm("" : "=r" (v) : "0" (x)); \
52 ((v - VSYSCALL_FIRST_PAGE) + __pa_symbol(&__vsyscall_0)); }) 52 ((v - VSYSCALL_FIRST_PAGE) + __pa_symbol(&__vsyscall_0)); })
53 53
54/*
55 * vsyscall_gtod_data contains data that is :
56 * - readonly from vsyscalls
57 * - writen by timer interrupt or systcl (/proc/sys/kernel/vsyscall64)
58 * Try to keep this structure as small as possible to avoid cache line ping pongs
59 */
54struct vsyscall_gtod_data_t { 60struct vsyscall_gtod_data_t {
55 seqlock_t lock; 61 seqlock_t lock;
56 int sysctl_enabled; 62
57 struct timeval wall_time_tv; 63 /* open coded 'struct timespec' */
64 time_t wall_time_sec;
65 u32 wall_time_nsec;
66
67 int sysctl_enabled;
58 struct timezone sys_tz; 68 struct timezone sys_tz;
59 cycle_t offset_base; 69 struct { /* extract of a clocksource struct */
60 struct clocksource clock; 70 cycle_t (*vread)(void);
71 cycle_t cycle_last;
72 cycle_t mask;
73 u32 mult;
74 u32 shift;
75 } clock;
61}; 76};
62int __vgetcpu_mode __section_vgetcpu_mode; 77int __vgetcpu_mode __section_vgetcpu_mode;
63 78
@@ -73,9 +88,13 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
73 88
74 write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags); 89 write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags);
75 /* copy vsyscall data */ 90 /* copy vsyscall data */
76 vsyscall_gtod_data.clock = *clock; 91 vsyscall_gtod_data.clock.vread = clock->vread;
77 vsyscall_gtod_data.wall_time_tv.tv_sec = wall_time->tv_sec; 92 vsyscall_gtod_data.clock.cycle_last = clock->cycle_last;
78 vsyscall_gtod_data.wall_time_tv.tv_usec = wall_time->tv_nsec/1000; 93 vsyscall_gtod_data.clock.mask = clock->mask;
94 vsyscall_gtod_data.clock.mult = clock->mult;
95 vsyscall_gtod_data.clock.shift = clock->shift;
96 vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec;
97 vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
79 vsyscall_gtod_data.sys_tz = sys_tz; 98 vsyscall_gtod_data.sys_tz = sys_tz;
80 write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags); 99 write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
81} 100}
@@ -110,7 +129,8 @@ static __always_inline long time_syscall(long *t)
110static __always_inline void do_vgettimeofday(struct timeval * tv) 129static __always_inline void do_vgettimeofday(struct timeval * tv)
111{ 130{
112 cycle_t now, base, mask, cycle_delta; 131 cycle_t now, base, mask, cycle_delta;
113 unsigned long seq, mult, shift, nsec_delta; 132 unsigned seq;
133 unsigned long mult, shift, nsec;
114 cycle_t (*vread)(void); 134 cycle_t (*vread)(void);
115 do { 135 do {
116 seq = read_seqbegin(&__vsyscall_gtod_data.lock); 136 seq = read_seqbegin(&__vsyscall_gtod_data.lock);
@@ -126,21 +146,20 @@ static __always_inline void do_vgettimeofday(struct timeval * tv)
126 mult = __vsyscall_gtod_data.clock.mult; 146 mult = __vsyscall_gtod_data.clock.mult;
127 shift = __vsyscall_gtod_data.clock.shift; 147 shift = __vsyscall_gtod_data.clock.shift;
128 148
129 *tv = __vsyscall_gtod_data.wall_time_tv; 149 tv->tv_sec = __vsyscall_gtod_data.wall_time_sec;
130 150 nsec = __vsyscall_gtod_data.wall_time_nsec;
131 } while (read_seqretry(&__vsyscall_gtod_data.lock, seq)); 151 } while (read_seqretry(&__vsyscall_gtod_data.lock, seq));
132 152
133 /* calculate interval: */ 153 /* calculate interval: */
134 cycle_delta = (now - base) & mask; 154 cycle_delta = (now - base) & mask;
135 /* convert to nsecs: */ 155 /* convert to nsecs: */
136 nsec_delta = (cycle_delta * mult) >> shift; 156 nsec += (cycle_delta * mult) >> shift;
137 157
138 /* convert to usecs and add to timespec: */ 158 while (nsec >= NSEC_PER_SEC) {
139 tv->tv_usec += nsec_delta / NSEC_PER_USEC;
140 while (tv->tv_usec > USEC_PER_SEC) {
141 tv->tv_sec += 1; 159 tv->tv_sec += 1;
142 tv->tv_usec -= USEC_PER_SEC; 160 nsec -= NSEC_PER_SEC;
143 } 161 }
162 tv->tv_usec = nsec / NSEC_PER_USEC;
144} 163}
145 164
146int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz) 165int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
@@ -159,7 +178,7 @@ time_t __vsyscall(1) vtime(time_t *t)
159 time_t result; 178 time_t result;
160 if (unlikely(!__vsyscall_gtod_data.sysctl_enabled)) 179 if (unlikely(!__vsyscall_gtod_data.sysctl_enabled))
161 return time_syscall(t); 180 return time_syscall(t);
162 result = __vsyscall_gtod_data.wall_time_tv.tv_sec; 181 result = __vsyscall_gtod_data.wall_time_sec;
163 if (t) 182 if (t)
164 *t = result; 183 *t = result;
165 return result; 184 return result;