Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0696b711 authored by Lin Ming's avatar Lin Ming Committed by Thomas Gleixner
Browse files

timekeeping: Fix clock_gettime vsyscall time warp



Since commit 0a544198 "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: default avatarLin 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: default avatarThomas Gleixner <tglx@linutronix.de>
parent a9366e61
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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;
+3 −2
Original line number Diff line number Diff line
@@ -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;

@@ -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;
+2 −1
Original line number Diff line number Diff line
@@ -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;
+3 −2
Original line number Diff line number Diff line
@@ -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;
+4 −2
Original line number Diff line number Diff line
@@ -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)
{
}

Loading