Skip to content

Commit

Permalink
timekeeping: Fix clock_gettime vsyscall time warp
Browse files Browse the repository at this point in the history
Since commit 0a54419 "timekeeping: Move NTP adjusted clock multiplier
to struct timekeeper" the clock multiplier of vsyscall is updated with
the unmodified clock multiplier of the clock source and not with the
NTP adjusted multiplier of the timekeeper.

This causes user space observerable time warps:
new CLOCK-warp maximum: 120 nsecs,  00000025c337c537 -> 00000025c337c4bf

Add a new argument "mult" to update_vsyscall() and hand in the
timekeeping internal NTP adjusted multiplier.

Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Cc: "Zhang Yanmin" <yanmin_zhang@linux.intel.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Tony Luck <tony.luck@intel.com>
LKML-Reference: <1258436990.17765.83.camel@minggr.sh.intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
Lin Ming authored and Thomas Gleixner committed Nov 17, 2009
1 parent a9366e6 commit 0696b71
Show file tree
Hide file tree
Showing 6 changed files with 17 additions and 12 deletions.
4 changes: 2 additions & 2 deletions arch/ia64/kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -473,15 +473,15 @@ void update_vsyscall_tz(void)
{
}

void update_vsyscall(struct timespec *wall, struct clocksource *c)
void update_vsyscall(struct timespec *wall, struct clocksource *c, u32 mult)
{
unsigned long flags;

write_seqlock_irqsave(&fsyscall_gtod_data.lock, flags);

/* copy fsyscall clock data */
fsyscall_gtod_data.clk_mask = c->mask;
fsyscall_gtod_data.clk_mult = c->mult;
fsyscall_gtod_data.clk_mult = mult;
fsyscall_gtod_data.clk_shift = c->shift;
fsyscall_gtod_data.clk_fsys_mmio = c->fsys_mmio;
fsyscall_gtod_data.clk_cycle_last = c->cycle_last;
Expand Down
5 changes: 3 additions & 2 deletions arch/powerpc/kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,8 @@ static cycle_t timebase_read(struct clocksource *cs)
return (cycle_t)get_tb();
}

void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
void update_vsyscall(struct timespec *wall_time, struct clocksource *clock,
u32 mult)
{
u64 t2x, stamp_xsec;

Expand All @@ -841,7 +842,7 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)

/* XXX this assumes clock->shift == 22 */
/* 4611686018 ~= 2^(20+64-22) / 1e9 */
t2x = (u64) clock->mult * 4611686018ULL;
t2x = (u64) mult * 4611686018ULL;
stamp_xsec = (u64) xtime.tv_nsec * XSEC_PER_SEC;
do_div(stamp_xsec, 1000000000);
stamp_xsec += (u64) xtime.tv_sec * XSEC_PER_SEC;
Expand Down
3 changes: 2 additions & 1 deletion arch/s390/kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,8 @@ struct clocksource * __init clocksource_default_clock(void)
return &clocksource_tod;
}

void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
void update_vsyscall(struct timespec *wall_time, struct clocksource *clock,
u32 mult)
{
if (clock != &clocksource_tod)
return;
Expand Down
5 changes: 3 additions & 2 deletions arch/x86/kernel/vsyscall_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ void update_vsyscall_tz(void)
write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
}

void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
void update_vsyscall(struct timespec *wall_time, struct clocksource *clock,
u32 mult)
{
unsigned long flags;

Expand All @@ -82,7 +83,7 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
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.mult = 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;
Expand Down
6 changes: 4 additions & 2 deletions include/linux/clocksource.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,12 @@ extern struct clocksource * __init __weak clocksource_default_clock(void);
extern void clocksource_mark_unstable(struct clocksource *cs);

#ifdef CONFIG_GENERIC_TIME_VSYSCALL
extern void update_vsyscall(struct timespec *ts, struct clocksource *c);
extern void
update_vsyscall(struct timespec *ts, struct clocksource *c, u32 mult);
extern void update_vsyscall_tz(void);
#else
static inline void update_vsyscall(struct timespec *ts, struct clocksource *c)
static inline void
update_vsyscall(struct timespec *ts, struct clocksource *c, u32 mult)
{
}

Expand Down
6 changes: 3 additions & 3 deletions kernel/time/timekeeping.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ void timekeeping_leap_insert(int leapsecond)
{
xtime.tv_sec += leapsecond;
wall_to_monotonic.tv_sec -= leapsecond;
update_vsyscall(&xtime, timekeeper.clock);
update_vsyscall(&xtime, timekeeper.clock, timekeeper.mult);
}

#ifdef CONFIG_GENERIC_TIME
Expand Down Expand Up @@ -337,7 +337,7 @@ int do_settimeofday(struct timespec *tv)
timekeeper.ntp_error = 0;
ntp_clear();

update_vsyscall(&xtime, timekeeper.clock);
update_vsyscall(&xtime, timekeeper.clock, timekeeper.mult);

write_sequnlock_irqrestore(&xtime_lock, flags);

Expand Down Expand Up @@ -811,7 +811,7 @@ void update_wall_time(void)
update_xtime_cache(nsecs);

/* check to see if there is a new clocksource to use */
update_vsyscall(&xtime, timekeeper.clock);
update_vsyscall(&xtime, timekeeper.clock, timekeeper.mult);
}

/**
Expand Down

0 comments on commit 0696b71

Please sign in to comment.