This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH 08/19] y2038: introduce struct __kernel_timespec
- From: Arnd Bergmann <arnd at arndb dot de>
- To: y2038 at lists dot linaro dot org
- Cc: baolin dot wang at linaro dot org, tglx at linutronix dot de, albert dot aribaud at 3adev dot fr, john dot stultz at linaro dot org, bamvor dot zhangjian at linaro dot org, ruchandani dot tina at gmail dot com, linux-api at vger dot kernel dot org, linux-kernel at vger dot kernel dot org, libc-alpha at sourceware dot org, Arnd Bergmann <arnd at arndb dot de>
- Date: Wed, 6 May 2015 18:30:15 +0200
- Subject: [PATCH 08/19] y2038: introduce struct __kernel_timespec
- Authentication-results: sourceware.org; auth=none
- References: <1430929826-318934-1-git-send-email-arnd at arndb dot de>
A lot of system calls pass a 'struct timespec' from or to user space,
and we want to change that type to be based on a 64-bit time_t by
default.
This introduces a new type struct __kernel_timespec, which has the
format we want to use eventually, but also has an override so all
architectures that do not define CONFIG_COMPAT_TIME yet still get the
old behavior.
Once all architectures set this, we can remove that override.
This also introduces a get_timespec64/put_timespec64 set of functions
that convert between a __kernel_timespec in user space and a timespec64
in kernel space.
The current behavior of get_timespec64 explicitly zeroes the upper half
of the tv_nsec member, to allow user space to define its own 'struct
timespec' with some padding in it. Whether this is a good or bad idea
is open for discussion.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
include/linux/time64.h | 17 +++++++++++------
include/uapi/linux/time.h | 17 +++++++++++++++++
kernel/time/time.c | 32 ++++++++++++++++++++++++++++++++
3 files changed, 60 insertions(+), 6 deletions(-)
diff --git a/include/linux/time64.h b/include/linux/time64.h
index a3831478d9cf..880ebe4b4ba4 100644
--- a/include/linux/time64.h
+++ b/include/linux/time64.h
@@ -1,14 +1,12 @@
#ifndef _LINUX_TIME64_H
#define _LINUX_TIME64_H
-#include <uapi/linux/time.h>
-
typedef __s64 time64_t;
-/*
- * This wants to go into uapi/linux/time.h once we agreed about the
- * userspace interfaces.
- */
+#ifndef CONFIG_COMPAT_TIME
+# define __kernel_timespec timespec
+#endif
+
#if __BITS_PER_LONG == 64
# define timespec64 timespec
#else
@@ -18,6 +16,8 @@ struct timespec64 {
};
#endif
+#include <uapi/linux/time.h>
+
/* Parameters used to convert the timespec values: */
#define MSEC_PER_SEC 1000L
#define USEC_PER_MSEC 1000L
@@ -187,4 +187,9 @@ static __always_inline void timespec64_add_ns(struct timespec64 *a, u64 ns)
#endif
+extern int get_timespec64(struct timespec64 *ts,
+ const struct __kernel_timespec __user *uts);
+extern int put_timespec64(const struct timespec64 *ts,
+ struct __kernel_timespec __user *uts);
+
#endif /* _LINUX_TIME64_H */
diff --git a/include/uapi/linux/time.h b/include/uapi/linux/time.h
index e75e1b6ff27f..72d894df3013 100644
--- a/include/uapi/linux/time.h
+++ b/include/uapi/linux/time.h
@@ -66,4 +66,21 @@ struct itimerval {
*/
#define TIMER_ABSTIME 0x01
+/* types based on 64-bit time_t */
+#ifndef __kernel_timespec
+typedef __s64 __kernel_time64_t;
+
+struct __kernel_timespec {
+ __kernel_time64_t tv_sec;
+ __s64 tv_nsec;
+};
+#endif
+
+#ifndef __kernel_itimerspec
+struct __kernel_itimerspec {
+ struct __kernel_timespec it_interval;
+ struct __kernel_timespec it_value;
+};
+#endif
+
#endif /* _UAPI_LINUX_TIME_H */
diff --git a/kernel/time/time.c b/kernel/time/time.c
index 2c85b7724af4..845af1db66fa 100644
--- a/kernel/time/time.c
+++ b/kernel/time/time.c
@@ -30,6 +30,7 @@
#include <linux/export.h>
#include <linux/timex.h>
#include <linux/capability.h>
+#include <linux/compat.h>
#include <linux/timekeeper_internal.h>
#include <linux/errno.h>
#include <linux/syscalls.h>
@@ -37,6 +38,7 @@
#include <linux/fs.h>
#include <linux/math64.h>
#include <linux/ptrace.h>
+#include <linux/time64.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -783,3 +785,33 @@ struct timespec timespec_add_safe(const struct timespec lhs,
return res;
}
+
+int get_timespec64(struct timespec64 *ts,
+ const struct __kernel_timespec __user *uts)
+{
+ struct __kernel_timespec kts;
+ int ret;
+
+ ret = copy_from_user(&kts, uts, sizeof(kts));
+ if (ret)
+ return -EFAULT;
+
+ ts->tv_sec = kts.tv_sec;
+ if (!IS_ENABLED(CONFIG_64BIT) || is_compat_task())
+ kts.tv_nsec &= 0xfffffffful;
+ ts->tv_nsec = kts.tv_nsec;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(get_timespec64);
+
+int put_timespec64(const struct timespec64 *ts,
+ struct __kernel_timespec __user *uts)
+{
+ struct __kernel_timespec kts = {
+ .tv_sec = ts->tv_sec,
+ .tv_nsec = ts->tv_nsec
+ };
+ return copy_to_user(uts, &kts, sizeof(kts)) ? -EFAULT : 0;
+}
+EXPORT_SYMBOL_GPL(put_timespec64);
--
2.1.0.rc2