Browse Source

Fix adjtimex() with TIME64

When UCLIBC_USE_TIME64 is enabled on a 32-bit target, "struct timex"
does not match the kernel definition of the struct. As a result,
functions adjtimex() and clock_adjtime() misbehave. This causes failure
of NTP clients such as Chrony.

This patch changes the definition of "struct timex" to match the 64-bit
kernel definition when UCLIBC_USE_TIME64 is defined. This form of the
struct is suitable for syscall clock_adjtime64(). Otherwise, when TIME64
is disabled, "struct timex" remains unchanged in the form suitable for
syscall clock_adjtime().

Note that recent versions of glibc use a similar conditional definition
of "struct timex".

Furthermore, this patch implements adjtimex() by calling clock_adjtime().
This works because clock_adjtime() resolves to clock_adjtime64() when
TIME64 is defined. Redirecting to clock_adjtime() is necessary because
there is no adjtimex64() syscall.

An early draft of this patch was proposed by Waldemar Brodkorb.
I added the change in "struct timex" and tested that this works with and
without TIME64.

Signed-off-by: Joris van Rantwijk <joris@jorisvr.nl>
Joris van Rantwijk 1 day ago
parent
commit
fc43f3fc0c
2 changed files with 35 additions and 6 deletions
  1. 34 0
      include/sys/timex.h
  2. 1 6
      libc/sysdeps/linux/common/adjtimex.c

+ 34 - 0
include/sys/timex.h

@@ -33,6 +33,39 @@ struct ntptimeval
 
 struct timex
 {
+#ifdef __UCLIBC_USE_TIME64__
+  unsigned int modes;	/* mode selector */
+  int :32;
+  long long offset;	/* time offset (usec) */
+  long long freq;	/* frequency offset (scaled ppm) */
+  long long maxerror;	/* maximum error (usec) */
+  long long esterror;	/* estimated error (usec) */
+  int status;		/* clock command/status */
+  int :32;
+  long long constant;	/* pll time constant */
+  long long precision;	/* clock precision (usec) (read only) */
+  long long tolerance;	/* clock frequency tolerance (ppm) (read only) */
+  struct timeval time;	/* (read only) */
+  long long tick;	/* (modified) usecs between clock ticks */
+  long long ppsfreq;	/* pps frequency (scaled ppm) (ro) */
+  long long jitter;	/* pps jitter (us) (ro) */
+  int shift;		/* interval duration (s) (shift) (ro) */
+  int :32;
+  long long stabil;	/* pps stability (scaled ppm) (ro) */
+  long long jitcnt;	/* jitter limit exceeded (ro) */
+  long long calcnt;	/* calibration intervals (ro) */
+  long long errcnt;	/* calibration errors (ro) */
+  long long stbcnt;	/* stability limit exceeded (ro) */
+
+  int tai;		/* TAI offset (ro) */
+
+  /* ??? */
+  int  :32; int  :32; int  :32; int  :32;
+  int  :32; int  :32; int  :32; int  :32;
+  int  :32; int  :32; int  :32;
+
+#else
+
   unsigned int modes;	/* mode selector */
   long int offset;	/* time offset (usec) */
   long int freq;	/* frequency offset (scaled ppm) */
@@ -59,6 +92,7 @@ struct timex
   int  :32; int  :32; int  :32; int  :32;
   int  :32; int  :32; int  :32; int  :32;
   int  :32; int  :32; int  :32; int  :32;
+#endif
 };
 
 /* Mode codes (timex.mode) */

+ 1 - 6
libc/sysdeps/linux/common/adjtimex.c

@@ -6,18 +6,13 @@
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  */
 
-#include <sys/syscall.h>
 #include <sys/timex.h>
-
-#if defined(__NR_adjtimex)
-_syscall1(int, adjtimex, struct timex *, buf)
-#else
 #include <time.h>
+
 int adjtimex(struct timex *buf)
 {
     return clock_adjtime(CLOCK_REALTIME, buf);
 }
-#endif
 
 libc_hidden_def(adjtimex)
 weak_alias(adjtimex,__adjtimex)