mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 21:07:02 +09:00
timekeeping: Fix clock_gettime vsyscall time warp
commit0696b711e4upstream. Since commit0a544198"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> Signed-off-by: Kurt Garloff <garloff@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
e66bb88311
commit
8aa3149405
@@ -473,7 +473,7 @@ 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;
|
||||
|
||||
@@ -481,7 +481,7 @@ void update_vsyscall(struct timespec *wall, struct clocksource *c)
|
||||
|
||||
/* 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;
|
||||
|
||||
@@ -864,7 +864,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;
|
||||
|
||||
@@ -877,7 +878,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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -282,10 +282,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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -822,7 +822,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user