]> err.no Git - linux-2.6/blobdiff - arch/x86_64/kernel/vsyscall.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[linux-2.6] / arch / x86_64 / kernel / vsyscall.c
index ba330f87067996a17495f7d03466d646c718b52c..06c34949bfdc9d09e90a219765aeb711c67e85a4 100644 (file)
@@ -42,6 +42,7 @@
 #include <asm/segment.h>
 #include <asm/desc.h>
 #include <asm/topology.h>
+#include <asm/vgtod.h>
 
 #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
 #define __syscall_clobber "r11","rcx","memory"
          asm("" : "=r" (v) : "0" (x)); \
          ((v - VSYSCALL_FIRST_PAGE) + __pa_symbol(&__vsyscall_0)); })
 
-struct vsyscall_gtod_data_t {
-       seqlock_t lock;
-       int sysctl_enabled;
-       struct timeval wall_time_tv;
-       struct timezone sys_tz;
-       cycle_t offset_base;
-       struct clocksource clock;
-};
+/*
+ * vsyscall_gtod_data contains data that is :
+ * - readonly from vsyscalls
+ * - writen by timer interrupt or systcl (/proc/sys/kernel/vsyscall64)
+ * Try to keep this structure as small as possible to avoid cache line ping pongs
+ */
 int __vgetcpu_mode __section_vgetcpu_mode;
 
-struct vsyscall_gtod_data_t __vsyscall_gtod_data __section_vsyscall_gtod_data =
+struct vsyscall_gtod_data __vsyscall_gtod_data __section_vsyscall_gtod_data =
 {
        .lock = SEQLOCK_UNLOCKED,
        .sysctl_enabled = 1,
@@ -73,10 +72,16 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
 
        write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags);
        /* copy vsyscall data */
-       vsyscall_gtod_data.clock = *clock;
-       vsyscall_gtod_data.wall_time_tv.tv_sec = wall_time->tv_sec;
-       vsyscall_gtod_data.wall_time_tv.tv_usec = wall_time->tv_nsec/1000;
+       vsyscall_gtod_data.clock.vread = clock->vread;
+       vsyscall_gtod_data.clock.cycle_last = clock->cycle_last;
+       vsyscall_gtod_data.clock.mask = clock->mask;
+       vsyscall_gtod_data.clock.mult = clock->mult;
+       vsyscall_gtod_data.clock.shift = clock->shift;
+       vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec;
+       vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
        vsyscall_gtod_data.sys_tz = sys_tz;
+       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);
 }
 
@@ -110,7 +115,8 @@ static __always_inline long time_syscall(long *t)
 static __always_inline void do_vgettimeofday(struct timeval * tv)
 {
        cycle_t now, base, mask, cycle_delta;
-       unsigned long seq, mult, shift, nsec_delta;
+       unsigned seq;
+       unsigned long mult, shift, nsec;
        cycle_t (*vread)(void);
        do {
                seq = read_seqbegin(&__vsyscall_gtod_data.lock);
@@ -126,21 +132,20 @@ static __always_inline void do_vgettimeofday(struct timeval * tv)
                mult = __vsyscall_gtod_data.clock.mult;
                shift = __vsyscall_gtod_data.clock.shift;
 
-               *tv = __vsyscall_gtod_data.wall_time_tv;
-
+               tv->tv_sec = __vsyscall_gtod_data.wall_time_sec;
+               nsec = __vsyscall_gtod_data.wall_time_nsec;
        } while (read_seqretry(&__vsyscall_gtod_data.lock, seq));
 
        /* calculate interval: */
        cycle_delta = (now - base) & mask;
        /* convert to nsecs: */
-       nsec_delta = (cycle_delta * mult) >> shift;
+       nsec += (cycle_delta * mult) >> shift;
 
-       /* convert to usecs and add to timespec: */
-       tv->tv_usec += nsec_delta / NSEC_PER_USEC;
-       while (tv->tv_usec > USEC_PER_SEC) {
+       while (nsec >= NSEC_PER_SEC) {
                tv->tv_sec += 1;
-               tv->tv_usec -= USEC_PER_SEC;
+               nsec -= NSEC_PER_SEC;
        }
+       tv->tv_usec = nsec / NSEC_PER_USEC;
 }
 
 int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
@@ -156,10 +161,13 @@ int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
  * unlikely */
 time_t __vsyscall(1) vtime(time_t *t)
 {
+       struct timeval tv;
        time_t result;
        if (unlikely(!__vsyscall_gtod_data.sysctl_enabled))
                return time_syscall(t);
-       result = __vsyscall_gtod_data.wall_time_tv.tv_sec;
+
+       vgettimeofday(&tv, 0);
+       result = tv.tv_sec;
        if (t)
                *t = result;
        return result;
@@ -308,7 +316,7 @@ static int __cpuinit
 cpu_vsyscall_notifier(struct notifier_block *n, unsigned long action, void *arg)
 {
        long cpu = (long)arg;
-       if (action == CPU_ONLINE)
+       if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN)
                smp_call_function_single(cpu, cpu_vsyscall_init, NULL, 0, 1);
        return NOTIFY_DONE;
 }