From patchwork Wed May 6 16:30:15 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 6592 Received: (qmail 109857 invoked by alias); 6 May 2015 16:36:05 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 109782 invoked by uid 89); 6 May 2015 16:36:04 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.6 required=5.0 tests=AWL, BAYES_50, KAM_LAZY_DOMAIN_SECURITY, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.2 X-HELO: mout.kundenserver.de From: Arnd Bergmann To: y2038@lists.linaro.org Cc: baolin.wang@linaro.org, tglx@linutronix.de, albert.aribaud@3adev.fr, john.stultz@linaro.org, bamvor.zhangjian@linaro.org, ruchandani.tina@gmail.com, linux-api@vger.kernel.org, linux-kernel@vger.kernel.org, libc-alpha@sourceware.org, Arnd Bergmann Subject: [PATCH 08/19] y2038: introduce struct __kernel_timespec Date: Wed, 6 May 2015 18:30:15 +0200 Message-Id: <1430929826-318934-9-git-send-email-arnd@arndb.de> In-Reply-To: <1430929826-318934-1-git-send-email-arnd@arndb.de> References: <1430929826-318934-1-git-send-email-arnd@arndb.de> X-UI-Out-Filterresults: notjunk:1; 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 --- 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 - 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 + /* 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 #include #include +#include #include #include #include @@ -37,6 +38,7 @@ #include #include #include +#include #include #include @@ -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);