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

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

Commit Message

Lukasz Majewski April 26, 2020, 1:31 p.m.
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

-- 
2.20.1

Comments

Noah Goldstein via Libc-alpha April 27, 2020, 10:12 p.m. | #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

>
Noah Goldstein via Libc-alpha April 28, 2020, 5 p.m. | #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. | #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

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