diff mbox series

[04/10] y2038: linux: Provide __clock_adjtime64 implementation

Message ID 20200426133110.5312-5-lukma@denx.de
State New
Headers show
Series y2038: Convert clock_adjtime related syscalls to support 64 bit time | expand

Commit Message

Lukasz Majewski April 26, 2020, 1:31 p.m. UTC
This patch replaces auto generated wrapper (as described in
sysdeps/unix/sysv/linux/syscalls.list) for clock_adjtime with one which adds
extra support for reading 64 bit time values on machines with __TIMESIZE != 64.

To achieve this goal new __clock_adjtime64 explicit 64 bit function for
adjusting Linux clock has been added.
Moreover, a 32 bit version - __clock_adjtime has been refactored to internally
use __clock_adjtime64.

The __clock_adjtime is now supposed to be used on systems still supporting 32
bit time (__TIMESIZE != 64) - hence the necessary conversions between 64 bit
struct __timespec64 and struct timespec.

The new __clock_adjtime64 syscall available from Linux 5.1+ has been used, when
applicable.
Up till v5.4 in the Linux kernel there was a bug preventing this call from
obtaining correct struct's timex time.tv_sec time after time_t overflow
(i.e. not being Y2038 safe).

Build tests:
- ./src/scripts/build-many-glibcs.py glibcs

Run-time tests:
- Run specific tests on ARM/x86 32bit systems (qemu):
  https://github.com/lmajewski/meta-y2038 and run tests:
  https://github.com/lmajewski/y2038-tests/commits/master

Linux kernel, headers and minimal kernel version for glibc build test matrix:
- Linux v5.1 (with clock_adjtime64) and glibc build with v5.1 as
  minimal kernel version (--enable-kernel="5.1.0")
  The __ASSUME_TIME64_SYSCALLS flag defined.

- Linux v5.1 and default minimal kernel version
  The __ASSUME_TIME64_SYSCALLS not defined, but kernel supports clock_adjtime64
  syscall.

- Linux v4.19 (no clock_adjtime64 support) with default minimal kernel version
  for contemporary glibc (3.2.0)
  This kernel doesn't support clock_adjtime64 syscall, so the fallback to
  clock_adjtime is tested.

Above tests were performed with Y2038 redirection applied as well as without
(so the __TIMESIZE != 64 execution path is checked as well).

No regressions were observed.
---
 sysdeps/unix/sysv/linux/Makefile            |  2 +-
 sysdeps/unix/sysv/linux/clock_adjtime.c     | 64 +++++++++++++++++++++
 sysdeps/unix/sysv/linux/include/sys/timex.h |  3 +
 sysdeps/unix/sysv/linux/syscalls.list       |  1 -
 4 files changed, 68 insertions(+), 2 deletions(-)
 create mode 100644 sysdeps/unix/sysv/linux/clock_adjtime.c

Comments

Alistair Francis April 27, 2020, 10:12 p.m. UTC | #1
On Sun, Apr 26, 2020 at 6:31 AM Lukasz Majewski <lukma@denx.de> wrote:
>
> This patch replaces auto generated wrapper (as described in
> sysdeps/unix/sysv/linux/syscalls.list) for clock_adjtime with one which adds
> extra support for reading 64 bit time values on machines with __TIMESIZE != 64.
>
> To achieve this goal new __clock_adjtime64 explicit 64 bit function for
> adjusting Linux clock has been added.
> Moreover, a 32 bit version - __clock_adjtime has been refactored to internally
> use __clock_adjtime64.
>
> The __clock_adjtime is now supposed to be used on systems still supporting 32
> bit time (__TIMESIZE != 64) - hence the necessary conversions between 64 bit
> struct __timespec64 and struct timespec.
>
> The new __clock_adjtime64 syscall available from Linux 5.1+ has been used, when
> applicable.
> Up till v5.4 in the Linux kernel there was a bug preventing this call from
> obtaining correct struct's timex time.tv_sec time after time_t overflow
> (i.e. not being Y2038 safe).
>
> Build tests:
> - ./src/scripts/build-many-glibcs.py glibcs
>
> Run-time tests:
> - Run specific tests on ARM/x86 32bit systems (qemu):
>   https://github.com/lmajewski/meta-y2038 and run tests:
>   https://github.com/lmajewski/y2038-tests/commits/master
>
> Linux kernel, headers and minimal kernel version for glibc build test matrix:
> - Linux v5.1 (with clock_adjtime64) and glibc build with v5.1 as
>   minimal kernel version (--enable-kernel="5.1.0")
>   The __ASSUME_TIME64_SYSCALLS flag defined.
>
> - Linux v5.1 and default minimal kernel version
>   The __ASSUME_TIME64_SYSCALLS not defined, but kernel supports clock_adjtime64
>   syscall.
>
> - Linux v4.19 (no clock_adjtime64 support) with default minimal kernel version
>   for contemporary glibc (3.2.0)
>   This kernel doesn't support clock_adjtime64 syscall, so the fallback to
>   clock_adjtime is tested.
>
> Above tests were performed with Y2038 redirection applied as well as without
> (so the __TIMESIZE != 64 execution path is checked as well).
>
> No regressions were observed.

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  sysdeps/unix/sysv/linux/Makefile            |  2 +-
>  sysdeps/unix/sysv/linux/clock_adjtime.c     | 64 +++++++++++++++++++++
>  sysdeps/unix/sysv/linux/include/sys/timex.h |  3 +
>  sysdeps/unix/sysv/linux/syscalls.list       |  1 -
>  4 files changed, 68 insertions(+), 2 deletions(-)
>  create mode 100644 sysdeps/unix/sysv/linux/clock_adjtime.c
>
> diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
> index 089a4899d5..dfb200eccf 100644
> --- a/sysdeps/unix/sysv/linux/Makefile
> +++ b/sysdeps/unix/sysv/linux/Makefile
> @@ -59,7 +59,7 @@ sysdep_routines += adjtimex clone umount umount2 readahead sysctl \
>                    eventfd eventfd_read eventfd_write prlimit \
>                    personality epoll_wait tee vmsplice splice \
>                    open_by_handle_at mlock2 pkey_mprotect pkey_set pkey_get \
> -                  timerfd_gettime timerfd_settime
> +                  timerfd_gettime timerfd_settime clock_adjtime
>
>  CFLAGS-gethostid.c = -fexceptions
>  CFLAGS-tee.c = -fexceptions -fasynchronous-unwind-tables
> diff --git a/sysdeps/unix/sysv/linux/clock_adjtime.c b/sysdeps/unix/sysv/linux/clock_adjtime.c
> new file mode 100644
> index 0000000000..cbab6bf345
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/clock_adjtime.c
> @@ -0,0 +1,64 @@
> +/* clock_adjtime -- tune kernel clock
> +   Copyright (C) 2020 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public License as
> +   published by the Free Software Foundation; either version 2.1 of the
> +   License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; see the file COPYING.LIB.  If
> +   not, see <https://www.gnu.org/licenses/>.  */
> +
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <time.h>
> +#include <sysdep.h>
> +#include <sys/timex.h>
> +#include <kernel-features.h>
> +
> +int
> +__clock_adjtime64 (const clockid_t clock_id, struct __timex64 *tx64)
> +{
> +#ifdef __ASSUME_TIME64_SYSCALLS
> +# ifndef __NR_clock_adjtime64
> +#  define __NR_clock_adjtime64 __NR_clock_adjtime
> +# endif
> +       return INLINE_SYSCALL_CALL (clock_adjtime64, clock_id, tx64);
> +#else
> +  int ret = INLINE_SYSCALL_CALL (clock_adjtime64, clock_id, tx64);
> +  if ((ret >= TIME_OK && ret <= TIME_ERROR) || errno != ENOSYS)
> +    return ret;
> +
> +  struct timex tx32 = valid_timex64_to_timex (*tx64);
> +  int retval = INLINE_SYSCALL_CALL (clock_adjtime, clock_id, &tx32);
> +  *tx64 = valid_timex_to_timex64 (tx32);
> +
> +  return retval;
> +#endif
> +}
> +
> +#if __TIMESIZE != 64
> +libc_hidden_def (__clock_adjtime64)
> +
> +int
> +__clock_adjtime (const clockid_t clock_id, struct timex *tx)
> +{
> +       struct __timex64 tx64;
> +  int retval;
> +
> +  tx64 = valid_timex_to_timex64 (*tx);
> +  retval = __clock_adjtime64 (clock_id, &tx64);
> +  *tx = valid_timex64_to_timex (tx64);
> +
> +  return retval;
> +}
> +#endif
> +libc_hidden_def (__clock_adjtime);
> +strong_alias (__clock_adjtime, clock_adjtime)
> diff --git a/sysdeps/unix/sysv/linux/include/sys/timex.h b/sysdeps/unix/sysv/linux/include/sys/timex.h
> index bab6b28920..f1bb364db4 100644
> --- a/sysdeps/unix/sysv/linux/include/sys/timex.h
> +++ b/sysdeps/unix/sysv/linux/include/sys/timex.h
> @@ -30,6 +30,7 @@ libc_hidden_proto (__adjtimex)
>  /* Local definition of 64 bit time supporting timex struct */
>  #  if __TIMESIZE == 64
>  #   define __timex64 timex
> +#   define __clock_adjtime64 __clock_adjtime
>  #  else
>
>  struct __timex64
> @@ -63,6 +64,8 @@ struct __timex64
>    int  :32; int  :32; int  :32; int  :32;
>    int  :32; int  :32; int  :32;
>  };
> +extern int __clock_adjtime64 (const clockid_t clock_id, struct __timex64 *tx64);
> +libc_hidden_proto (__clock_adjtime64);
>  #  endif
>
>  /* Convert a known valid struct timex into a struct __timex64.  */
> diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list
> index e40f993495..d7d73e8fcb 100644
> --- a/sysdeps/unix/sysv/linux/syscalls.list
> +++ b/sysdeps/unix/sysv/linux/syscalls.list
> @@ -4,7 +4,6 @@ alarm           -       alarm           i:i     alarm
>  bdflush                EXTRA   bdflush         i:ii    __compat_bdflush        bdflush@GLIBC_2.0:GLIBC_2.23
>  capget         EXTRA   capget          i:pp    capget
>  capset         EXTRA   capset          i:pp    capset
> -clock_adjtime  EXTRA   clock_adjtime   i:ip    __clock_adjtime         clock_adjtime
>  create_module  EXTRA   create_module   3       __compat_create_module  create_module@GLIBC_2.0:GLIBC_2.23
>  delete_module  EXTRA   delete_module   3       delete_module
>  epoll_create   EXTRA   epoll_create    i:i     epoll_create
> --
> 2.20.1
>
Adhemerval Zanella Netto April 28, 2020, 5 p.m. UTC | #2
On 26/04/2020 10:31, Lukasz Majewski wrote:
> This patch replaces auto generated wrapper (as described in
> sysdeps/unix/sysv/linux/syscalls.list) for clock_adjtime with one which adds
> extra support for reading 64 bit time values on machines with __TIMESIZE != 64.
> 
> To achieve this goal new __clock_adjtime64 explicit 64 bit function for
> adjusting Linux clock has been added.
> Moreover, a 32 bit version - __clock_adjtime has been refactored to internally
> use __clock_adjtime64.
> 
> The __clock_adjtime is now supposed to be used on systems still supporting 32
> bit time (__TIMESIZE != 64) - hence the necessary conversions between 64 bit
> struct __timespec64 and struct timespec.
> 
> The new __clock_adjtime64 syscall available from Linux 5.1+ has been used, when
> applicable.
> Up till v5.4 in the Linux kernel there was a bug preventing this call from
> obtaining correct struct's timex time.tv_sec time after time_t overflow
> (i.e. not being Y2038 safe).
> 
> Build tests:
> - ./src/scripts/build-many-glibcs.py glibcs
> 
> Run-time tests:
> - Run specific tests on ARM/x86 32bit systems (qemu):
>   https://github.com/lmajewski/meta-y2038 and run tests:
>   https://github.com/lmajewski/y2038-tests/commits/master
> 
> Linux kernel, headers and minimal kernel version for glibc build test matrix:
> - Linux v5.1 (with clock_adjtime64) and glibc build with v5.1 as
>   minimal kernel version (--enable-kernel="5.1.0")
>   The __ASSUME_TIME64_SYSCALLS flag defined.
> 
> - Linux v5.1 and default minimal kernel version
>   The __ASSUME_TIME64_SYSCALLS not defined, but kernel supports clock_adjtime64
>   syscall.
> 
> - Linux v4.19 (no clock_adjtime64 support) with default minimal kernel version
>   for contemporary glibc (3.2.0)
>   This kernel doesn't support clock_adjtime64 syscall, so the fallback to
>   clock_adjtime is tested.
> 
> Above tests were performed with Y2038 redirection applied as well as without
> (so the __TIMESIZE != 64 execution path is checked as well).
> 
> No regressions were observed.
> ---
>  sysdeps/unix/sysv/linux/Makefile            |  2 +-
>  sysdeps/unix/sysv/linux/clock_adjtime.c     | 64 +++++++++++++++++++++
>  sysdeps/unix/sysv/linux/include/sys/timex.h |  3 +
>  sysdeps/unix/sysv/linux/syscalls.list       |  1 -
>  4 files changed, 68 insertions(+), 2 deletions(-)
>  create mode 100644 sysdeps/unix/sysv/linux/clock_adjtime.c
> 
> diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
> index 089a4899d5..dfb200eccf 100644
> --- a/sysdeps/unix/sysv/linux/Makefile
> +++ b/sysdeps/unix/sysv/linux/Makefile
> @@ -59,7 +59,7 @@ sysdep_routines += adjtimex clone umount umount2 readahead sysctl \
>  		   eventfd eventfd_read eventfd_write prlimit \
>  		   personality epoll_wait tee vmsplice splice \
>  		   open_by_handle_at mlock2 pkey_mprotect pkey_set pkey_get \
> -		   timerfd_gettime timerfd_settime
> +		   timerfd_gettime timerfd_settime clock_adjtime
>  
>  CFLAGS-gethostid.c = -fexceptions
>  CFLAGS-tee.c = -fexceptions -fasynchronous-unwind-tables

Ok.

> diff --git a/sysdeps/unix/sysv/linux/clock_adjtime.c b/sysdeps/unix/sysv/linux/clock_adjtime.c
> new file mode 100644
> index 0000000000..cbab6bf345
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/clock_adjtime.c
> @@ -0,0 +1,64 @@
> +/* clock_adjtime -- tune kernel clock
> +   Copyright (C) 2020 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public License as
> +   published by the Free Software Foundation; either version 2.1 of the
> +   License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; see the file COPYING.LIB.  If
> +   not, see <https://www.gnu.org/licenses/>.  */
> +
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <time.h>
> +#include <sysdep.h>
> +#include <sys/timex.h>
> +#include <kernel-features.h>
> +
> +int
> +__clock_adjtime64 (const clockid_t clock_id, struct __timex64 *tx64)
> +{
> +#ifdef __ASSUME_TIME64_SYSCALLS
> +# ifndef __NR_clock_adjtime64
> +#  define __NR_clock_adjtime64 __NR_clock_adjtime
> +# endif
> +	return INLINE_SYSCALL_CALL (clock_adjtime64, clock_id, tx64);

Ok.

> +#else
> +  int ret = INLINE_SYSCALL_CALL (clock_adjtime64, clock_id, tx64);
> +  if ((ret >= TIME_OK && ret <= TIME_ERROR) || errno != ENOSYS)
> +    return ret;

I see no point in issuing the non y2038 syscall for a return value not
in the define TIME_* constants.  I think so such cases it just return
the value to caller.

> +
> +  struct timex tx32 = valid_timex64_to_timex (*tx64);

This does not handle 'time' overflow for ADJ_SETOFFSET case (which might
ending setting an invalid time).  I think we should follow other y2038 
safe implementation and return EOVERFLOW in such case.  Something like:

  if (tx64->modes & ADJ_SETOFFSET
      && ! in_time_t_range (tx64.time.tv_sec))
    { 
      __set_errno (EOVERFLOW);
      return -1;
    }

> +  int retval = INLINE_SYSCALL_CALL (clock_adjtime, clock_id, &tx32);
> +  *tx64 = valid_timex_to_timex64 (tx32);
> +
> +  return retval;
> +#endif
> +}
> +
> +#if __TIMESIZE != 64
> +libc_hidden_def (__clock_adjtime64)
> +
> +int
> +__clock_adjtime (const clockid_t clock_id, struct timex *tx)
> +{
> +	struct __timex64 tx64;

Wrong identation.

> +  int retval;
> +
> +  tx64 = valid_timex_to_timex64 (*tx);
> +  retval = __clock_adjtime64 (clock_id, &tx64);
> +  *tx = valid_timex64_to_timex (tx64);
> +
> +  return retval;
> +}
> +#endif> +libc_hidden_def (__clock_adjtime);
> +strong_alias (__clock_adjtime, clock_adjtime)

Ok.

> diff --git a/sysdeps/unix/sysv/linux/include/sys/timex.h b/sysdeps/unix/sysv/linux/include/sys/timex.h
> index bab6b28920..f1bb364db4 100644
> --- a/sysdeps/unix/sysv/linux/include/sys/timex.h
> +++ b/sysdeps/unix/sysv/linux/include/sys/timex.h
> @@ -30,6 +30,7 @@ libc_hidden_proto (__adjtimex)
>  /* Local definition of 64 bit time supporting timex struct */
>  #  if __TIMESIZE == 64
>  #   define __timex64 timex
> +#   define __clock_adjtime64 __clock_adjtime
>  #  else
>  

Ok.

>  struct __timex64
> @@ -63,6 +64,8 @@ struct __timex64
>    int  :32; int  :32; int  :32; int  :32;
>    int  :32; int  :32; int  :32;
>  };
> +extern int __clock_adjtime64 (const clockid_t clock_id, struct __timex64 *tx64);
> +libc_hidden_proto (__clock_adjtime64);
>  #  endif
>  
>  /* Convert a known valid struct timex into a struct __timex64.  */

Ok.

> diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list
> index e40f993495..d7d73e8fcb 100644
> --- a/sysdeps/unix/sysv/linux/syscalls.list
> +++ b/sysdeps/unix/sysv/linux/syscalls.list
> @@ -4,7 +4,6 @@ alarm		-	alarm		i:i	alarm
>  bdflush		EXTRA	bdflush		i:ii	__compat_bdflush	bdflush@GLIBC_2.0:GLIBC_2.23
>  capget		EXTRA	capget		i:pp	capget
>  capset		EXTRA	capset		i:pp	capset
> -clock_adjtime	EXTRA	clock_adjtime	i:ip	__clock_adjtime		clock_adjtime
>  create_module	EXTRA	create_module	3	__compat_create_module	create_module@GLIBC_2.0:GLIBC_2.23
>  delete_module	EXTRA	delete_module	3	delete_module
>  epoll_create	EXTRA	epoll_create	i:i	epoll_create
> 

Ok.
Lukasz Majewski April 29, 2020, 9:43 p.m. UTC | #3
Hi Adhemerval,

> On 26/04/2020 10:31, Lukasz Majewski wrote:
> > This patch replaces auto generated wrapper (as described in
> > sysdeps/unix/sysv/linux/syscalls.list) for clock_adjtime with one
> > which adds extra support for reading 64 bit time values on machines
> > with __TIMESIZE != 64.
> > 
> > To achieve this goal new __clock_adjtime64 explicit 64 bit function
> > for adjusting Linux clock has been added.
> > Moreover, a 32 bit version - __clock_adjtime has been refactored to
> > internally use __clock_adjtime64.
> > 
> > The __clock_adjtime is now supposed to be used on systems still
> > supporting 32 bit time (__TIMESIZE != 64) - hence the necessary
> > conversions between 64 bit struct __timespec64 and struct timespec.
> > 
> > The new __clock_adjtime64 syscall available from Linux 5.1+ has
> > been used, when applicable.
> > Up till v5.4 in the Linux kernel there was a bug preventing this
> > call from obtaining correct struct's timex time.tv_sec time after
> > time_t overflow (i.e. not being Y2038 safe).
> > 
> > Build tests:
> > - ./src/scripts/build-many-glibcs.py glibcs
> > 
> > Run-time tests:
> > - Run specific tests on ARM/x86 32bit systems (qemu):
> >   https://github.com/lmajewski/meta-y2038 and run tests:
> >   https://github.com/lmajewski/y2038-tests/commits/master
> > 
> > Linux kernel, headers and minimal kernel version for glibc build
> > test matrix:
> > - Linux v5.1 (with clock_adjtime64) and glibc build with v5.1 as
> >   minimal kernel version (--enable-kernel="5.1.0")
> >   The __ASSUME_TIME64_SYSCALLS flag defined.
> > 
> > - Linux v5.1 and default minimal kernel version
> >   The __ASSUME_TIME64_SYSCALLS not defined, but kernel supports
> > clock_adjtime64 syscall.
> > 
> > - Linux v4.19 (no clock_adjtime64 support) with default minimal
> > kernel version for contemporary glibc (3.2.0)
> >   This kernel doesn't support clock_adjtime64 syscall, so the
> > fallback to clock_adjtime is tested.
> > 
> > Above tests were performed with Y2038 redirection applied as well
> > as without (so the __TIMESIZE != 64 execution path is checked as
> > well).
> > 
> > No regressions were observed.
> > ---
> >  sysdeps/unix/sysv/linux/Makefile            |  2 +-
> >  sysdeps/unix/sysv/linux/clock_adjtime.c     | 64
> > +++++++++++++++++++++ sysdeps/unix/sysv/linux/include/sys/timex.h |
> >  3 + sysdeps/unix/sysv/linux/syscalls.list       |  1 -
> >  4 files changed, 68 insertions(+), 2 deletions(-)
> >  create mode 100644 sysdeps/unix/sysv/linux/clock_adjtime.c
> > 
> > diff --git a/sysdeps/unix/sysv/linux/Makefile
> > b/sysdeps/unix/sysv/linux/Makefile index 089a4899d5..dfb200eccf
> > 100644 --- a/sysdeps/unix/sysv/linux/Makefile
> > +++ b/sysdeps/unix/sysv/linux/Makefile
> > @@ -59,7 +59,7 @@ sysdep_routines += adjtimex clone umount umount2
> > readahead sysctl \ eventfd eventfd_read eventfd_write prlimit \
> >  		   personality epoll_wait tee vmsplice splice \
> >  		   open_by_handle_at mlock2 pkey_mprotect pkey_set
> > pkey_get \
> > -		   timerfd_gettime timerfd_settime
> > +		   timerfd_gettime timerfd_settime clock_adjtime
> >  
> >  CFLAGS-gethostid.c = -fexceptions
> >  CFLAGS-tee.c = -fexceptions -fasynchronous-unwind-tables  
> 
> Ok.
> 
> > diff --git a/sysdeps/unix/sysv/linux/clock_adjtime.c
> > b/sysdeps/unix/sysv/linux/clock_adjtime.c new file mode 100644
> > index 0000000000..cbab6bf345
> > --- /dev/null
> > +++ b/sysdeps/unix/sysv/linux/clock_adjtime.c
> > @@ -0,0 +1,64 @@
> > +/* clock_adjtime -- tune kernel clock
> > +   Copyright (C) 2020 Free Software Foundation, Inc.
> > +   This file is part of the GNU C Library.
> > +
> > +   The GNU C Library is free software; you can redistribute it
> > and/or
> > +   modify it under the terms of the GNU Lesser General Public
> > License as
> > +   published by the Free Software Foundation; either version 2.1
> > of the
> > +   License, or (at your option) any later version.
> > +
> > +   The GNU C Library is distributed in the hope that it will be
> > useful,
> > +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > GNU
> > +   Lesser General Public License for more details.
> > +
> > +   You should have received a copy of the GNU Lesser General Public
> > +   License along with the GNU C Library; see the file COPYING.LIB.
> >  If
> > +   not, see <https://www.gnu.org/licenses/>.  */
> > +
> > +#include <errno.h>
> > +#include <stdlib.h>
> > +#include <time.h>
> > +#include <sysdep.h>
> > +#include <sys/timex.h>
> > +#include <kernel-features.h>
> > +
> > +int
> > +__clock_adjtime64 (const clockid_t clock_id, struct __timex64
> > *tx64) +{
> > +#ifdef __ASSUME_TIME64_SYSCALLS
> > +# ifndef __NR_clock_adjtime64
> > +#  define __NR_clock_adjtime64 __NR_clock_adjtime
> > +# endif
> > +	return INLINE_SYSCALL_CALL (clock_adjtime64, clock_id,
> > tx64);  
> 
> Ok.
> 
> > +#else
> > +  int ret = INLINE_SYSCALL_CALL (clock_adjtime64, clock_id, tx64);
> > +  if ((ret >= TIME_OK && ret <= TIME_ERROR) || errno != ENOSYS)
> > +    return ret;  
> 
> I see no point in issuing the non y2038 syscall for a return value not
> in the define TIME_* constants.  I think so such cases it just return
> the value to caller.

Could you be more specific?

We do call 32 bit clock_adjtime only when:

- ret is not in correct TIME_* range

or

- errno == ENOSYS (not available on the system due to old kernel)


Would you instead prefer to just have:

if (errno != ENOSYS)
  return ret;


> 
> > +
> > +  struct timex tx32 = valid_timex64_to_timex (*tx64);  
> 
> This does not handle 'time' overflow for ADJ_SETOFFSET case (which
> might ending setting an invalid time).  I think we should follow
> other y2038 safe implementation and return EOVERFLOW in such case.
> Something like:
> 
>   if (tx64->modes & ADJ_SETOFFSET
>       && ! in_time_t_range (tx64.time.tv_sec))
>     { 
>       __set_errno (EOVERFLOW);
>       return -1;
>     }
> 

I've thought about it as well. 

However, the time.tv_{u}sec used when ADJ_SETOFFSET is set is only
added to the current kernel time [1]. It is very unlikely that we will
provide offset value, which would overflow 32 bits tv_sec.

However, if you prefer I can add the above check as well.

[1] - http://man7.org/linux/man-pages/man2/adjtimex.2.html

> > +  int retval = INLINE_SYSCALL_CALL (clock_adjtime, clock_id,
> > &tx32);
> > +  *tx64 = valid_timex_to_timex64 (tx32);
> > +
> > +  return retval;
> > +#endif
> > +}
> > +
> > +#if __TIMESIZE != 64
> > +libc_hidden_def (__clock_adjtime64)
> > +
> > +int
> > +__clock_adjtime (const clockid_t clock_id, struct timex *tx)
> > +{
> > +	struct __timex64 tx64;  
> 
> Wrong identation.
> 

I will double check it.

> > +  int retval;
> > +
> > +  tx64 = valid_timex_to_timex64 (*tx);
> > +  retval = __clock_adjtime64 (clock_id, &tx64);
> > +  *tx = valid_timex64_to_timex (tx64);
> > +
> > +  return retval;
> > +}  
> > +#endif> +libc_hidden_def (__clock_adjtime);  
> > +strong_alias (__clock_adjtime, clock_adjtime)  
> 
> Ok.
> 
> > diff --git a/sysdeps/unix/sysv/linux/include/sys/timex.h
> > b/sysdeps/unix/sysv/linux/include/sys/timex.h index
> > bab6b28920..f1bb364db4 100644 ---
> > a/sysdeps/unix/sysv/linux/include/sys/timex.h +++
> > b/sysdeps/unix/sysv/linux/include/sys/timex.h @@ -30,6 +30,7 @@
> > libc_hidden_proto (__adjtimex) /* Local definition of 64 bit time
> > supporting timex struct */ #  if __TIMESIZE == 64
> >  #   define __timex64 timex
> > +#   define __clock_adjtime64 __clock_adjtime
> >  #  else
> >    
> 
> Ok.
> 
> >  struct __timex64
> > @@ -63,6 +64,8 @@ struct __timex64
> >    int  :32; int  :32; int  :32; int  :32;
> >    int  :32; int  :32; int  :32;
> >  };
> > +extern int __clock_adjtime64 (const clockid_t clock_id, struct
> > __timex64 *tx64); +libc_hidden_proto (__clock_adjtime64);
> >  #  endif
> >  
> >  /* Convert a known valid struct timex into a struct __timex64.  */
> >  
> 
> Ok.
> 
> > diff --git a/sysdeps/unix/sysv/linux/syscalls.list
> > b/sysdeps/unix/sysv/linux/syscalls.list index
> > e40f993495..d7d73e8fcb 100644 ---
> > a/sysdeps/unix/sysv/linux/syscalls.list +++
> > b/sysdeps/unix/sysv/linux/syscalls.list @@ -4,7 +4,6 @@
> > alarm		-	alarm		i:i	alarm
> > bdflush		EXTRA	bdflush
> > i:ii	__compat_bdflush	bdflush@GLIBC_2.0:GLIBC_2.23
> > capget		EXTRA	capget
> > i:pp	capget capset		EXTRA	capset
> > 	i:pp	capset -clock_adjtime	EXTRA
> > clock_adjtime	i:ip	__clock_adjtime
> > clock_adjtime create_module	EXTRA
> > create_module	3	__compat_create_module
> > create_module@GLIBC_2.0:GLIBC_2.23 delete_module
> > EXTRA	delete_module	3	delete_module
> > epoll_create	EXTRA	epoll_create	i:i
> > epoll_create 
> 
> Ok.




Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
diff mbox series

Patch

diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 089a4899d5..dfb200eccf 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -59,7 +59,7 @@  sysdep_routines += adjtimex clone umount umount2 readahead sysctl \
 		   eventfd eventfd_read eventfd_write prlimit \
 		   personality epoll_wait tee vmsplice splice \
 		   open_by_handle_at mlock2 pkey_mprotect pkey_set pkey_get \
-		   timerfd_gettime timerfd_settime
+		   timerfd_gettime timerfd_settime clock_adjtime
 
 CFLAGS-gethostid.c = -fexceptions
 CFLAGS-tee.c = -fexceptions -fasynchronous-unwind-tables
diff --git a/sysdeps/unix/sysv/linux/clock_adjtime.c b/sysdeps/unix/sysv/linux/clock_adjtime.c
new file mode 100644
index 0000000000..cbab6bf345
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/clock_adjtime.c
@@ -0,0 +1,64 @@ 
+/* clock_adjtime -- tune kernel clock
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, see <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sysdep.h>
+#include <sys/timex.h>
+#include <kernel-features.h>
+
+int
+__clock_adjtime64 (const clockid_t clock_id, struct __timex64 *tx64)
+{
+#ifdef __ASSUME_TIME64_SYSCALLS
+# ifndef __NR_clock_adjtime64
+#  define __NR_clock_adjtime64 __NR_clock_adjtime
+# endif
+	return INLINE_SYSCALL_CALL (clock_adjtime64, clock_id, tx64);
+#else
+  int ret = INLINE_SYSCALL_CALL (clock_adjtime64, clock_id, tx64);
+  if ((ret >= TIME_OK && ret <= TIME_ERROR) || errno != ENOSYS)
+    return ret;
+
+  struct timex tx32 = valid_timex64_to_timex (*tx64);
+  int retval = INLINE_SYSCALL_CALL (clock_adjtime, clock_id, &tx32);
+  *tx64 = valid_timex_to_timex64 (tx32);
+
+  return retval;
+#endif
+}
+
+#if __TIMESIZE != 64
+libc_hidden_def (__clock_adjtime64)
+
+int
+__clock_adjtime (const clockid_t clock_id, struct timex *tx)
+{
+	struct __timex64 tx64;
+  int retval;
+
+  tx64 = valid_timex_to_timex64 (*tx);
+  retval = __clock_adjtime64 (clock_id, &tx64);
+  *tx = valid_timex64_to_timex (tx64);
+
+  return retval;
+}
+#endif
+libc_hidden_def (__clock_adjtime);
+strong_alias (__clock_adjtime, clock_adjtime)
diff --git a/sysdeps/unix/sysv/linux/include/sys/timex.h b/sysdeps/unix/sysv/linux/include/sys/timex.h
index bab6b28920..f1bb364db4 100644
--- a/sysdeps/unix/sysv/linux/include/sys/timex.h
+++ b/sysdeps/unix/sysv/linux/include/sys/timex.h
@@ -30,6 +30,7 @@  libc_hidden_proto (__adjtimex)
 /* Local definition of 64 bit time supporting timex struct */
 #  if __TIMESIZE == 64
 #   define __timex64 timex
+#   define __clock_adjtime64 __clock_adjtime
 #  else
 
 struct __timex64
@@ -63,6 +64,8 @@  struct __timex64
   int  :32; int  :32; int  :32; int  :32;
   int  :32; int  :32; int  :32;
 };
+extern int __clock_adjtime64 (const clockid_t clock_id, struct __timex64 *tx64);
+libc_hidden_proto (__clock_adjtime64);
 #  endif
 
 /* Convert a known valid struct timex into a struct __timex64.  */
diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list
index e40f993495..d7d73e8fcb 100644
--- a/sysdeps/unix/sysv/linux/syscalls.list
+++ b/sysdeps/unix/sysv/linux/syscalls.list
@@ -4,7 +4,6 @@  alarm		-	alarm		i:i	alarm
 bdflush		EXTRA	bdflush		i:ii	__compat_bdflush	bdflush@GLIBC_2.0:GLIBC_2.23
 capget		EXTRA	capget		i:pp	capget
 capset		EXTRA	capset		i:pp	capset
-clock_adjtime	EXTRA	clock_adjtime	i:ip	__clock_adjtime		clock_adjtime
 create_module	EXTRA	create_module	3	__compat_create_module	create_module@GLIBC_2.0:GLIBC_2.23
 delete_module	EXTRA	delete_module	3	delete_module
 epoll_create	EXTRA	epoll_create	i:i	epoll_create