d39c24f5c2
The update of the VDSO data is depending on __arch_use_vsyscall() returning True. This is a leftover from the attempt to map the features of various architectures 1:1 into generic code. The usage of __arch_use_vsyscall() in the actual vsyscall implementations got dropped and replaced by the requirement for the architecture code to return U64_MAX if the global clocksource is not usable in the VDSO. But the __arch_use_vsyscall() check in the update code stayed which causes the VDSO data to be stale or invalid when an architecture actually implements that function and returns False when the current clocksource is not usable in the VDSO. As a consequence the VDSO implementations of clock_getres(), time(), clock_gettime(CLOCK_.*_COARSE) operate on invalid data and return bogus information. Remove the __arch_use_vsyscall() check from the VDSO update function and update the VDSO data unconditionally. [ tglx: Massaged changelog and removed the now useless implementations in asm-generic/ARM64/MIPS ] Fixes: 44f57d788e7deecb50 ("timekeeping: Provide a generic update_vsyscall() implementation") Signed-off-by: Huacai Chen <chenhc@lemote.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Andy Lutomirski <luto@kernel.org> Cc: Vincenzo Frascino <vincenzo.frascino@arm.com> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Paul Burton <paul.burton@mips.com> Cc: linux-mips@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/1571887709-11447-1-git-send-email-chenhc@lemote.com (cherry picked from commit 52338415cf4d4064ae6b8dd972dadbda841da4fa) Signed-off-by: Mark Salyzyn <salyzyn@google.com> Bug: 158635600 Bug: 154668398 Bug: 157925983 Change-Id: I71691d3011a96256d1ce01718d3f0fdc0778920e
130 lines
3.7 KiB
C
130 lines
3.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright 2019 ARM Ltd.
|
|
*
|
|
* Generic implementation of update_vsyscall and update_vsyscall_tz.
|
|
*
|
|
* Based on the x86 specific implementation.
|
|
*/
|
|
|
|
#include <linux/hrtimer.h>
|
|
#include <linux/timekeeper_internal.h>
|
|
#include <vdso/datapage.h>
|
|
#include <vdso/helpers.h>
|
|
#include <vdso/vsyscall.h>
|
|
|
|
static inline void update_vdso_data(struct vdso_data *vdata,
|
|
struct timekeeper *tk)
|
|
{
|
|
struct vdso_timestamp *vdso_ts;
|
|
u64 nsec;
|
|
|
|
vdata[CS_HRES_COARSE].cycle_last = tk->tkr_mono.cycle_last;
|
|
vdata[CS_HRES_COARSE].mask = tk->tkr_mono.mask;
|
|
vdata[CS_HRES_COARSE].mult = tk->tkr_mono.mult;
|
|
vdata[CS_HRES_COARSE].shift = tk->tkr_mono.shift;
|
|
vdata[CS_RAW].cycle_last = tk->tkr_raw.cycle_last;
|
|
vdata[CS_RAW].mask = tk->tkr_raw.mask;
|
|
vdata[CS_RAW].mult = tk->tkr_raw.mult;
|
|
vdata[CS_RAW].shift = tk->tkr_raw.shift;
|
|
|
|
/* CLOCK_REALTIME */
|
|
vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_REALTIME];
|
|
vdso_ts->sec = tk->xtime_sec;
|
|
vdso_ts->nsec = tk->tkr_mono.xtime_nsec;
|
|
|
|
/* CLOCK_MONOTONIC */
|
|
vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_MONOTONIC];
|
|
vdso_ts->sec = tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
|
|
|
|
nsec = tk->tkr_mono.xtime_nsec;
|
|
nsec += ((u64)tk->wall_to_monotonic.tv_nsec << tk->tkr_mono.shift);
|
|
while (nsec >= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) {
|
|
nsec -= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift);
|
|
vdso_ts->sec++;
|
|
}
|
|
vdso_ts->nsec = nsec;
|
|
|
|
/* CLOCK_MONOTONIC_RAW */
|
|
vdso_ts = &vdata[CS_RAW].basetime[CLOCK_MONOTONIC_RAW];
|
|
vdso_ts->sec = tk->raw_sec;
|
|
vdso_ts->nsec = tk->tkr_raw.xtime_nsec;
|
|
|
|
/* CLOCK_BOOTTIME */
|
|
vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_BOOTTIME];
|
|
vdso_ts->sec = tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
|
|
nsec = tk->tkr_mono.xtime_nsec;
|
|
nsec += ((u64)(tk->wall_to_monotonic.tv_nsec +
|
|
ktime_to_ns(tk->offs_boot)) << tk->tkr_mono.shift);
|
|
while (nsec >= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) {
|
|
nsec -= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift);
|
|
vdso_ts->sec++;
|
|
}
|
|
vdso_ts->nsec = nsec;
|
|
|
|
/* CLOCK_TAI */
|
|
vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_TAI];
|
|
vdso_ts->sec = tk->xtime_sec + (s64)tk->tai_offset;
|
|
vdso_ts->nsec = tk->tkr_mono.xtime_nsec;
|
|
|
|
/*
|
|
* Read without the seqlock held by clock_getres().
|
|
* Note: No need to have a second copy.
|
|
*/
|
|
WRITE_ONCE(vdata[CS_HRES_COARSE].hrtimer_res, hrtimer_resolution);
|
|
}
|
|
|
|
void update_vsyscall(struct timekeeper *tk)
|
|
{
|
|
struct vdso_data *vdata = __arch_get_k_vdso_data();
|
|
struct vdso_timestamp *vdso_ts;
|
|
u64 nsec;
|
|
|
|
if (__arch_update_vdso_data()) {
|
|
/*
|
|
* Some architectures might want to skip the update of the
|
|
* data page.
|
|
*/
|
|
return;
|
|
}
|
|
|
|
/* copy vsyscall data */
|
|
vdso_write_begin(vdata);
|
|
|
|
vdata[CS_HRES_COARSE].clock_mode = __arch_get_clock_mode(tk);
|
|
vdata[CS_RAW].clock_mode = __arch_get_clock_mode(tk);
|
|
|
|
/* CLOCK_REALTIME_COARSE */
|
|
vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_REALTIME_COARSE];
|
|
vdso_ts->sec = tk->xtime_sec;
|
|
vdso_ts->nsec = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift;
|
|
|
|
/* CLOCK_MONOTONIC_COARSE */
|
|
vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_MONOTONIC_COARSE];
|
|
vdso_ts->sec = tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
|
|
nsec = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift;
|
|
nsec = nsec + tk->wall_to_monotonic.tv_nsec;
|
|
while (nsec >= NSEC_PER_SEC) {
|
|
nsec = nsec - NSEC_PER_SEC;
|
|
vdso_ts->sec++;
|
|
}
|
|
vdso_ts->nsec = nsec;
|
|
|
|
update_vdso_data(vdata, tk);
|
|
|
|
__arch_update_vsyscall(vdata, tk);
|
|
|
|
vdso_write_end(vdata);
|
|
|
|
__arch_sync_vdso_data(vdata);
|
|
}
|
|
|
|
void update_vsyscall_tz(void)
|
|
{
|
|
struct vdso_data *vdata = __arch_get_k_vdso_data();
|
|
|
|
vdata[CS_HRES_COARSE].tz_minuteswest = sys_tz.tz_minuteswest;
|
|
vdata[CS_HRES_COARSE].tz_dsttime = sys_tz.tz_dsttime;
|
|
|
|
__arch_sync_vdso_data(vdata);
|
|
}
|