diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2014-01-30 21:02:00 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2014-01-30 21:02:00 +0000 |
commit | e161f073d9835d140e4f863d20a63ab15cfd9092 (patch) | |
tree | ebe8bc731574b977dfe3a3c6fbcfb3d69fc6bbb8 /sys | |
parent | 02c86de9dd6a2ec2439cef966e81dce0d33fb73f (diff) |
Simplyfy adjtime(2) by keeping track of the adjustment as a number of
microsecond in a 64-bit integer. Fixes the issue where ntpd loses sync
because the struct timeval currently used to hold the adjustment is not
properly normalized after the changes guenther@ made.
ok guenther@, millert@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_tc.c | 21 | ||||
-rw-r--r-- | sys/kern/kern_time.c | 41 | ||||
-rw-r--r-- | sys/sys/kernel.h | 6 |
3 files changed, 30 insertions, 38 deletions
diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c index 241aaa9e080..4d112aa4966 100644 --- a/sys/kern/kern_tc.c +++ b/sys/kern/kern_tc.c @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $OpenBSD: kern_tc.c,v 1.21 2013/10/06 01:27:49 guenther Exp $ + * $OpenBSD: kern_tc.c,v 1.22 2014/01/30 21:01:59 kettenis Exp $ * $FreeBSD: src/sys/kern/kern_tc.c,v 1.148 2003/03/18 08:45:23 phk Exp $ */ @@ -611,20 +611,15 @@ sysctl_tc(int *name, u_int namelen, void *oldp, size_t *oldlenp, void ntp_update_second(int64_t *adjust, time_t *sec) { - struct timeval adj; + int64_t adj; /* Skew time according to any adjtime(2) adjustments. */ - timerclear(&adj); - if (adjtimedelta.tv_sec > 0) - adj.tv_usec = 5000; - else if (adjtimedelta.tv_sec == 0) - adj.tv_usec = MIN(5000, adjtimedelta.tv_usec); - else if (adjtimedelta.tv_sec < -1) - adj.tv_usec = -5000; - else if (adjtimedelta.tv_sec == -1) - adj.tv_usec = MAX(-5000, adjtimedelta.tv_usec - 1000000); - timersub(&adjtimedelta, &adj, &adjtimedelta); - *adjust = ((int64_t)adj.tv_usec * 1000) << 32; + if (adjtimedelta > 0) + adj = MIN(5000, adjtimedelta); + else + adj = MAX(-5000, adjtimedelta); + adjtimedelta -= adj; + *adjust = (adj * 1000) << 32; *adjust += timecounter->tc_freq_adj; } diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index 858d860b50f..f48c3a2af86 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_time.c,v 1.86 2014/01/22 00:48:36 guenther Exp $ */ +/* $OpenBSD: kern_time.c,v 1.87 2014/01/30 21:01:59 kettenis Exp $ */ /* $NetBSD: kern_time.c,v 1.20 1996/02/18 11:57:06 fvdl Exp $ */ /* @@ -46,7 +46,7 @@ #include <sys/syscallargs.h> -struct timeval adjtimedelta; /* unapplied time correction */ +int64_t adjtimedelta; /* unapplied time correction (microseconds) */ /* * Time of day and interval timer support. @@ -68,8 +68,7 @@ settime(struct timespec *ts) * Adjtime in progress is meaningless or harmful after * setting the clock. Cancel adjtime and then set new time. */ - adjtimedelta.tv_usec = 0; - adjtimedelta.tv_sec = 0; + adjtimedelta = 0; /* * Don't allow the time to be set forward so far it will wrap @@ -428,37 +427,35 @@ sys_adjtime(struct proc *p, void *v, register_t *retval) syscallarg(const struct timeval *) delta; syscallarg(struct timeval *) olddelta; } */ *uap = v; - struct timeval newdelta; const struct timeval *delta = SCARG(uap, delta); struct timeval *olddelta = SCARG(uap, olddelta); + struct timeval atv; int error; - if (olddelta) - if ((error = copyout(&adjtimedelta, olddelta, - sizeof(struct timeval)))) + if (olddelta) { + memset(&atv, 0, sizeof(atv)); + atv.tv_sec = adjtimedelta / 1000000; + atv.tv_usec = adjtimedelta % 1000000; + if (atv.tv_usec < 0) { + atv.tv_usec += 1000000; + atv.tv_sec--; + } + + if ((error = copyout(&atv, olddelta, sizeof(struct timeval)))) return (error); + } if (delta) { if ((error = suser(p, 0))) return (error); - if ((error = copyin(delta, &newdelta, - sizeof(struct timeval)))) + if ((error = copyin(delta, &atv, sizeof(struct timeval)))) return (error); - /* Normalize the correction. */ - while (newdelta.tv_usec >= 1000000) { - newdelta.tv_usec -= 1000000; - newdelta.tv_sec += 1; - } - while (newdelta.tv_usec < 0) { - newdelta.tv_usec += 1000000; - newdelta.tv_sec -= 1; - } - - adjtimedelta.tv_sec = newdelta.tv_sec; - adjtimedelta.tv_usec = newdelta.tv_usec; + /* XXX Check for overflow? */ + adjtimedelta = (int64_t)atv.tv_sec * 1000000 + atv.tv_usec; } + return (0); } diff --git a/sys/sys/kernel.h b/sys/sys/kernel.h index 2668266c02c..292c4f82b39 100644 --- a/sys/sys/kernel.h +++ b/sys/sys/kernel.h @@ -1,4 +1,4 @@ -/* $OpenBSD: kernel.h,v 1.15 2013/10/06 01:27:49 guenther Exp $ */ +/* $OpenBSD: kernel.h,v 1.16 2014/01/30 21:01:59 kettenis Exp $ */ /* $NetBSD: kernel.h,v 1.11 1995/03/03 01:24:16 cgd Exp $ */ /*- @@ -61,5 +61,5 @@ extern int lbolt; /* once a second sleep address */ extern int tickdelta; extern long timedelta; -extern struct timeval adjtimedelta; /* unapplied time correction */ -extern struct bintime naptime; /* time spent suspended */ +extern int64_t adjtimedelta; /* unapplied time correction */ +extern struct bintime naptime; /* time spent suspended */ |