Commit 4dc1ffb5 authored by Philippe Gerum's avatar Philippe Gerum Committed by Jan Kiszka
Browse files

cobalt/kernel: y2038: convert struct timespec to timespec64



As internal interfaces are gradually being made y2038-safe, the
timespec64 type should be used internally by the kernel to represent
time values. Apply the same reasoning to Cobalt.

We still use a legacy y2038-unsafe timespec type at the kernel<->user
interface boundary (struct __user_old_timespec) until libcobalt is
y2038-safe.
Signed-off-by: Philippe Gerum's avatarPhilippe Gerum <rpm@xenomai.org>
[Florian: Fix regression in 32bit mode]
Signed-off-by: default avatarFlorian Bezdeka <florian.bezdeka@siemens.com>
Signed-off-by: Jan Kiszka's avatarJan Kiszka <jan.kiszka@siemens.com>
parent fa56fd74
......@@ -54,7 +54,7 @@ struct xnclock {
xnticks_t (*read_raw)(struct xnclock *clock);
xnticks_t (*read_monotonic)(struct xnclock *clock);
int (*set_time)(struct xnclock *clock,
const struct timespec *ts);
const struct timespec64 *ts);
xnsticks_t (*ns_to_ticks)(struct xnclock *clock,
xnsticks_t ns);
xnsticks_t (*ticks_to_ns)(struct xnclock *clock,
......@@ -211,7 +211,7 @@ static inline xnticks_t xnclock_read_monotonic(struct xnclock *clock)
}
static inline int xnclock_set_time(struct xnclock *clock,
const struct timespec *ts)
const struct timespec64 *ts)
{
if (likely(clock == &nkclock))
return -EINVAL;
......@@ -264,7 +264,7 @@ static inline xnticks_t xnclock_read_monotonic(struct xnclock *clock)
}
static inline int xnclock_set_time(struct xnclock *clock,
const struct timespec *ts)
const struct timespec64 *ts)
{
/*
* There is no way to change the core clock's idea of time.
......
......@@ -86,11 +86,11 @@ struct compat_rtdm_mmap_request {
int flags;
};
int sys32_get_timespec(struct timespec *ts,
int sys32_get_timespec(struct timespec64 *ts,
const struct compat_timespec __user *cts);
int sys32_put_timespec(struct compat_timespec __user *cts,
const struct timespec *ts);
const struct timespec64 *ts);
int sys32_get_itimerspec(struct itimerspec *its,
const struct compat_itimerspec __user *cits);
......
......@@ -8,7 +8,7 @@
#include <cobalt/uapi/kernel/types.h>
#include <cobalt/kernel/assert.h>
struct timespec;
struct timespec64;
static inline u64 pipeline_read_cycle_counter(void)
{
......@@ -49,7 +49,7 @@ static inline const char *pipeline_clock_name(void)
return "?";
}
static inline int pipeline_get_host_time(struct timespec *tp)
static inline int pipeline_get_host_time(struct timespec64 *tp)
{
/* Convert ktime_get_real_fast_ns() to timespec. */
TODO();
......
......@@ -7,7 +7,7 @@
#include <linux/ipipe_tickdev.h>
struct timespec;
struct timespec64;
static inline u64 pipeline_read_cycle_counter(void)
{
......@@ -31,7 +31,7 @@ static inline const char *pipeline_clock_name(void)
return ipipe_clock_name();
}
int pipeline_get_host_time(struct timespec *tp);
int pipeline_get_host_time(struct timespec64 *tp);
void pipeline_update_clock_freq(unsigned long long freq);
......
......@@ -380,7 +380,7 @@ int __rtdm_fd_recvmmsg(int ufd, void __user *u_msgvec, unsigned int vlen,
unsigned int flags, void __user *u_timeout,
int (*get_mmsg)(struct mmsghdr *mmsg, void __user *u_mmsg),
int (*put_mmsg)(void __user **u_mmsg_p, const struct mmsghdr *mmsg),
int (*get_timespec)(struct timespec *ts, const void __user *u_ts));
int (*get_timespec)(struct timespec64 *ts, const void __user *u_ts));
ssize_t rtdm_fd_sendmsg(int ufd, const struct user_msghdr *msg,
int flags);
......
......@@ -57,4 +57,14 @@ static inline xnhandle_t xnhandle_get_id(xnhandle_t handle)
return handle & ~XN_HANDLE_TRANSIENT_MASK;
}
/*
* Our representation of time at the kernel<->user interface boundary
* at the moment, until we have fully transitioned to a y2038-safe
* implementation in libcobalt.
*/
struct __user_old_timespec {
long tv_sec;
long tv_nsec;
};
#endif /* !_COBALT_UAPI_KERNEL_TYPES_H */
......@@ -18,6 +18,8 @@
#ifndef _COBALT_UAPI_SCHED_H
#define _COBALT_UAPI_SCHED_H
#include <cobalt/uapi/kernel/types.h>
#define SCHED_COBALT 42
#define SCHED_WEAK 43
......@@ -31,15 +33,15 @@
struct __sched_ss_param {
int __sched_low_priority;
struct timespec __sched_repl_period;
struct timespec __sched_init_budget;
struct __user_old_timespec __sched_repl_period;
struct __user_old_timespec __sched_init_budget;
int __sched_max_repl;
};
#define sched_rr_quantum sched_u.rr.__sched_rr_quantum
struct __sched_rr_param {
struct timespec __sched_rr_quantum;
struct __user_old_timespec __sched_rr_quantum;
};
#ifndef SCHED_TP
......@@ -52,8 +54,8 @@ struct __sched_tp_param {
};
struct sched_tp_window {
struct timespec offset;
struct timespec duration;
struct __user_old_timespec offset;
struct __user_old_timespec duration;
int ptid;
};
......
......@@ -26,6 +26,7 @@
#include <asm/xenomai/wrappers.h>
#include <asm/xenomai/machine.h>
#include <cobalt/uapi/asm-generic/syscall.h>
#include <cobalt/uapi/kernel/types.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
#define access_rok(addr, size) access_ok((addr), (size))
......@@ -81,6 +82,63 @@ static inline int cobalt_strncpy_from_user(char *dst, const char __user *src,
return __xn_strncpy_from_user(dst, src, count);
}
#if __BITS_PER_LONG == 64
/*
* NOTE: those copy helpers won't work in compat mode: use
* sys32_get_timespec(), sys32_put_timespec() instead.
*/
static inline int cobalt_get_u_timespec(struct timespec64 *dst,
const struct __user_old_timespec __user *src)
{
return cobalt_copy_from_user(dst, src, sizeof(*dst));
}
static inline int cobalt_put_u_timespec(
struct __user_old_timespec __user *dst,
const struct timespec64 *src)
{
return cobalt_copy_to_user(dst, src, sizeof(*dst));
}
#else /* __BITS_PER_LONG == 32 */
static inline int cobalt_get_u_timespec(struct timespec64 *dst,
const struct __user_old_timespec __user *src)
{
struct __user_old_timespec u_ts;
int ret;
ret = cobalt_copy_from_user(&u_ts, src, sizeof(u_ts));
if (ret)
return ret;
dst->tv_sec = u_ts.tv_sec;
dst->tv_nsec = u_ts.tv_nsec;
return 0;
}
static inline int cobalt_put_u_timespec(
struct __user_old_timespec __user *dst,
const struct timespec64 *src)
{
struct __user_old_timespec u_ts;
int ret;
u_ts.tv_sec = src->tv_sec;
u_ts.tv_nsec = src->tv_nsec;
ret = cobalt_copy_to_user(dst, &u_ts, sizeof(*dst));
if (ret)
return ret;
return 0;
}
#endif
/* 32bit syscall emulation */
#define __COBALT_COMPAT_BIT 0x1
/* 32bit syscall emulation - extended form */
......
......@@ -67,7 +67,7 @@ EXPORT_SYMBOL_GPL(xnclock_core_ticks_to_ns);
EXPORT_SYMBOL_GPL(xnclock_core_ticks_to_ns_rounded);
EXPORT_SYMBOL_GPL(xnclock_core_ns_to_ticks);
int pipeline_get_host_time(struct timespec *tp)
int pipeline_get_host_time(struct timespec64 *tp)
{
#ifdef CONFIG_IPIPE_HAVE_HOSTRT
struct xnvdso_hostrt_data *hostrt_data;
......
......@@ -51,7 +51,7 @@ DECLARE_BITMAP(cobalt_clock_extids, COBALT_MAX_EXTCLOCKS);
__val; \
})
int __cobalt_clock_getres(clockid_t clock_id, struct timespec *ts)
int __cobalt_clock_getres(clockid_t clock_id, struct timespec64 *ts)
{
xnticks_t ns;
int ret;
......@@ -75,16 +75,16 @@ int __cobalt_clock_getres(clockid_t clock_id, struct timespec *ts)
}
COBALT_SYSCALL(clock_getres, current,
(clockid_t clock_id, struct timespec __user *u_ts))
(clockid_t clock_id, struct __user_old_timespec __user *u_ts))
{
struct timespec ts;
struct timespec64 ts;
int ret;
ret = __cobalt_clock_getres(clock_id, &ts);
if (ret)
return ret;
if (u_ts && cobalt_copy_to_user(u_ts, &ts, sizeof(ts)))
if (u_ts && cobalt_put_u_timespec(u_ts, &ts))
return -EFAULT;
trace_cobalt_clock_getres(clock_id, &ts);
......@@ -92,7 +92,7 @@ COBALT_SYSCALL(clock_getres, current,
return 0;
}
int __cobalt_clock_gettime(clockid_t clock_id, struct timespec *ts)
int __cobalt_clock_gettime(clockid_t clock_id, struct timespec64 *ts)
{
xnticks_t ns;
int ret;
......@@ -122,16 +122,16 @@ int __cobalt_clock_gettime(clockid_t clock_id, struct timespec *ts)
}
COBALT_SYSCALL(clock_gettime, current,
(clockid_t clock_id, struct timespec __user *u_ts))
(clockid_t clock_id, struct __user_old_timespec __user *u_ts))
{
struct timespec ts;
struct timespec64 ts;
int ret;
ret = __cobalt_clock_gettime(clock_id, &ts);
if (ret)
return ret;
if (cobalt_copy_to_user(u_ts, &ts, sizeof(*u_ts)))
if (cobalt_put_u_timespec(u_ts, &ts))
return -EFAULT;
trace_cobalt_clock_gettime(clock_id, &ts);
......@@ -139,7 +139,7 @@ COBALT_SYSCALL(clock_gettime, current,
return 0;
}
int __cobalt_clock_settime(clockid_t clock_id, const struct timespec *ts)
int __cobalt_clock_settime(clockid_t clock_id, const struct timespec64 *ts)
{
int _ret, ret = 0;
xnticks_t now;
......@@ -188,11 +188,11 @@ int __cobalt_clock_adjtime(clockid_t clock_id, struct timex *tx)
}
COBALT_SYSCALL(clock_settime, current,
(clockid_t clock_id, const struct timespec __user *u_ts))
(clockid_t clock_id, const struct __user_old_timespec __user *u_ts))
{
struct timespec ts;
struct timespec64 ts;
if (cobalt_copy_from_user(&ts, u_ts, sizeof(ts)))
if (cobalt_get_u_timespec(&ts, u_ts))
return -EFAULT;
return __cobalt_clock_settime(clock_id, &ts);
......@@ -215,8 +215,8 @@ COBALT_SYSCALL(clock_adjtime, current,
}
int __cobalt_clock_nanosleep(clockid_t clock_id, int flags,
const struct timespec *rqt,
struct timespec *rmt)
const struct timespec64 *rqt,
struct timespec64 *rmt)
{
struct restart_block *restart;
struct xnthread *cur;
......@@ -296,21 +296,21 @@ int __cobalt_clock_nanosleep(clockid_t clock_id, int flags,
COBALT_SYSCALL(clock_nanosleep, primary,
(clockid_t clock_id, int flags,
const struct timespec __user *u_rqt,
struct timespec __user *u_rmt))
const struct __user_old_timespec __user *u_rqt,
struct __user_old_timespec __user *u_rmt))
{
struct timespec rqt, rmt, *rmtp = NULL;
struct timespec64 rqt, rmt, *rmtp = NULL;
int ret;
if (u_rmt)
rmtp = &rmt;
if (cobalt_copy_from_user(&rqt, u_rqt, sizeof(rqt)))
if (cobalt_get_u_timespec(&rqt, u_rqt))
return -EFAULT;
ret = __cobalt_clock_nanosleep(clock_id, flags, &rqt, rmtp);
if (ret == -EINTR && flags == 0 && rmtp) {
if (cobalt_copy_to_user(u_rmt, rmtp, sizeof(*u_rmt)))
if (cobalt_put_u_timespec(u_rmt, rmtp))
return -EFAULT;
}
......
......@@ -28,12 +28,27 @@
struct xnclock;
static inline void ns2ts(struct timespec *ts, xnticks_t nsecs)
static inline void ns2ts(struct timespec64 *ts, xnticks_t nsecs)
{
ts->tv_sec = xnclock_divrem_billion(nsecs, &ts->tv_nsec);
}
static inline xnticks_t ts2ns(const struct timespec *ts)
static inline void u_ns2ts(struct __user_old_timespec *ts, xnticks_t nsecs)
{
ts->tv_sec = xnclock_divrem_billion(nsecs, &ts->tv_nsec);
}
static inline xnticks_t ts2ns(const struct timespec64 *ts)
{
xnticks_t nsecs = ts->tv_nsec;
if (ts->tv_sec)
nsecs += (xnticks_t)ts->tv_sec * ONE_BILLION;
return nsecs;
}
static inline xnticks_t u_ts2ns(const struct __user_old_timespec *ts)
{
xnticks_t nsecs = ts->tv_nsec;
......@@ -80,37 +95,37 @@ static inline int clock_flag(int flag, clockid_t clock_id)
}
int __cobalt_clock_getres(clockid_t clock_id,
struct timespec *ts);
struct timespec64 *ts);
int __cobalt_clock_gettime(clockid_t clock_id,
struct timespec *ts);
struct timespec64 *ts);
int __cobalt_clock_settime(clockid_t clock_id,
const struct timespec *ts);
const struct timespec64 *ts);
int __cobalt_clock_adjtime(clockid_t clock_id,
struct timex *tx);
int __cobalt_clock_nanosleep(clockid_t clock_id, int flags,
const struct timespec *rqt,
struct timespec *rmt);
const struct timespec64 *rqt,
struct timespec64 *rmt);
COBALT_SYSCALL_DECL(clock_getres,
(clockid_t clock_id, struct timespec __user *u_ts));
(clockid_t clock_id, struct __user_old_timespec __user *u_ts));
COBALT_SYSCALL_DECL(clock_gettime,
(clockid_t clock_id, struct timespec __user *u_ts));
(clockid_t clock_id, struct __user_old_timespec __user *u_ts));
COBALT_SYSCALL_DECL(clock_settime,
(clockid_t clock_id, const struct timespec __user *u_ts));
(clockid_t clock_id, const struct __user_old_timespec __user *u_ts));
COBALT_SYSCALL_DECL(clock_adjtime,
(clockid_t clock_id, struct timex __user *u_tx));
COBALT_SYSCALL_DECL(clock_nanosleep,
(clockid_t clock_id, int flags,
const struct timespec __user *u_rqt,
struct timespec __user *u_rmt));
const struct __user_old_timespec __user *u_rqt,
struct __user_old_timespec __user *u_rmt));
int cobalt_clock_register(struct xnclock *clock,
const cpumask_t *affinity,
......
......@@ -22,23 +22,41 @@
#include <asm/xenomai/syscall.h>
#include <xenomai/posix/mqueue.h>
int sys32_get_timespec(struct timespec *ts,
const struct compat_timespec __user *cts)
int sys32_get_timespec(struct timespec64 *ts,
const struct compat_timespec __user *u_cts)
{
return (cts == NULL ||
!access_rok(cts, sizeof(*cts)) ||
__xn_get_user(ts->tv_sec, &cts->tv_sec) ||
__xn_get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
struct compat_timespec cts;
if (u_cts == NULL || !access_rok(u_cts, sizeof(*u_cts)))
return -EFAULT;
if (__xn_get_user(cts.tv_sec, &u_cts->tv_sec) ||
__xn_get_user(cts.tv_nsec, &u_cts->tv_nsec))
return -EFAULT;
ts->tv_sec = cts.tv_sec;
ts->tv_nsec = cts.tv_nsec;
return 0;
}
EXPORT_SYMBOL_GPL(sys32_get_timespec);
int sys32_put_timespec(struct compat_timespec __user *cts,
const struct timespec *ts)
int sys32_put_timespec(struct compat_timespec __user *u_cts,
const struct timespec64 *ts)
{
return (cts == NULL ||
!access_wok(cts, sizeof(*cts)) ||
__xn_put_user(ts->tv_sec, &cts->tv_sec) ||
__xn_put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
struct compat_timespec cts;
if (u_cts == NULL || !access_wok(u_cts, sizeof(*u_cts)))
return -EFAULT;
cts.tv_sec = ts->tv_sec;
cts.tv_nsec = ts->tv_nsec;
if (__xn_put_user(cts.tv_sec, &u_cts->tv_sec) ||
__xn_put_user(cts.tv_nsec, &u_cts->tv_nsec))
return -EFAULT;
return 0;
}
EXPORT_SYMBOL_GPL(sys32_put_timespec);
......@@ -478,7 +496,7 @@ int sys32_get_iovec(struct iovec *iov,
const struct compat_iovec __user *p;
struct compat_iovec ciov;
int ret, n;
for (n = 0, p = u_ciov; n < ciovlen; n++, p++) {
ret = cobalt_copy_from_user(&ciov, p, sizeof(ciov));
if (ret)
......@@ -498,7 +516,7 @@ int sys32_put_iovec(struct compat_iovec __user *u_ciov,
struct compat_iovec __user *p;
struct compat_iovec ciov;
int ret, n;
for (n = 0, p = u_ciov; n < iovlen; n++, p++) {
ciov.iov_base = ptr_to_compat(iov[n].iov_base);
ciov.iov_len = iov[n].iov_len;
......
......@@ -270,25 +270,24 @@ struct us_cond_data {
int err;
};
static inline int cond_fetch_timeout(struct timespec *ts,
static inline int cond_fetch_timeout(struct timespec64 *ts,
const void __user *u_ts)
{
return u_ts == NULL ? -EFAULT :
cobalt_copy_from_user(ts, u_ts, sizeof(*ts));
return u_ts == NULL ? -EFAULT : cobalt_get_u_timespec(ts, u_ts);
}
int __cobalt_cond_wait_prologue(struct cobalt_cond_shadow __user *u_cnd,
struct cobalt_mutex_shadow __user *u_mx,
int *u_err,
void __user *u_ts,
int (*fetch_timeout)(struct timespec *ts,
int (*fetch_timeout)(struct timespec64 *ts,
const void __user *u_ts))
{
struct xnthread *cur = xnthread_current();
struct cobalt_cond *cond;
struct cobalt_mutex *mx;
struct us_cond_data d;
struct timespec ts;
struct timespec64 ts;
xnhandle_t handle;
int err, perr = 0;
__u32 offset;
......@@ -349,7 +348,7 @@ COBALT_SYSCALL(cond_wait_prologue, nonrestartable,
struct cobalt_mutex_shadow __user *u_mx,
int *u_err,
unsigned int timed,
struct timespec __user *u_ts))
struct __user_old_timespec __user *u_ts))
{
return __cobalt_cond_wait_prologue(u_cnd, u_mx, u_err, u_ts,
timed ? cond_fetch_timeout : NULL);
......
......@@ -43,7 +43,7 @@ int __cobalt_cond_wait_prologue(struct cobalt_cond_shadow __user *u_cnd,
struct cobalt_mutex_shadow __user *u_mx,
int *u_err,
void __user *u_ts,
int (*fetch_timeout)(struct timespec *ts,
int (*fetch_timeout)(struct timespec64 *ts,
const void __user *u_ts));
COBALT_SYSCALL_DECL(cond_init,
(struct cobalt_cond_shadow __user *u_cnd,
......@@ -57,7 +57,7 @@ COBALT_SYSCALL_DECL(cond_wait_prologue,
struct cobalt_mutex_shadow __user *u_mx,
int *u_err,
unsigned int timed,
struct timespec __user *u_ts));
struct __user_old_timespec __user *u_ts));
COBALT_SYSCALL_DECL(cond_wait_epilogue,
(struct cobalt_cond_shadow __user *u_cnd,
......
......@@ -104,7 +104,7 @@ COBALT_SYSCALL(event_init, current,
int __cobalt_event_wait(struct cobalt_event_shadow __user *u_event,
unsigned int bits,
unsigned int __user *u_bits_r,
int mode, const struct timespec *ts)
int mode, const struct timespec64 *ts)
{
unsigned int rbits = 0, testval;
xnticks_t timeout = XN_INFINITE;
......@@ -193,14 +193,14 @@ COBALT_SYSCALL(event_wait, primary,
(struct cobalt_event_shadow __user *u_event,
unsigned int bits,
unsigned int __user *u_bits_r,
int mode, const struct timespec __user *u_ts))
int mode, const struct __user_old_timespec __user *u_ts))
{
struct timespec ts, *tsp = NULL;
struct timespec64 ts, *tsp = NULL;
int ret;
if (u_ts) {
tsp = &ts;
ret = cobalt_copy_from_user(&ts, u_ts, sizeof(ts));
ret = cobalt_get_u_timespec(&ts, u_ts);
if (ret)
return ret;
}
......
......@@ -39,7 +39,7 @@ struct cobalt_event {
int __cobalt_event_wait(struct cobalt_event_shadow __user *u_event,
unsigned int bits,
unsigned int __user *u_bits_r,
int mode, const struct timespec *ts);
int mode, const struct timespec64 *ts);
COBALT_SYSCALL_DECL(event_init,
(struct cobalt_event_shadow __user *u_evtsh,
......@@ -51,7 +51,7 @@ COBALT_SYSCALL_DECL(event_wait,
unsigned int bits,
unsigned int __user *u_bits_r,
int mode,
const struct timespec __user *u_ts));
const struct __user_old_timespec __user *u_ts));
COBALT_SYSCALL_DECL(event_sync,
(struct cobalt_event_shadow __user *u_evtsh));
......
......@@ -93,10 +93,10 @@ COBALT_SYSCALL(recvmsg, handover,
return cobalt_copy_to_user(umsg, &m, sizeof(*umsg)) ?: ret;
}
static int get_timespec(struct timespec *ts,
static int get_timespec(struct timespec64 *ts,
const void __user *u_ts)
{
return cobalt_copy_from_user(ts, u_ts, sizeof(*ts));
return cobalt_get_u_timespec(ts, u_ts);
}
static int get_mmsg(struct mmsghdr *mmsg, void __user *u_mmsg)
......@@ -114,7 +114,7 @@ static int put_mmsg(void __user **u_mmsg_p, const struct mmsghdr *mmsg)
COBALT_SYSCALL(recvmmsg, primary,
(int fd, struct mmsghdr __user *u_msgvec, unsigned int vlen,
unsigned int flags, struct timespec *u_timeout))
unsigned int flags, struct __user_old_timespec __user *u_timeout))