diff options
author | avg <avg@FreeBSD.org> | 2010-04-29 09:02:46 +0000 |
---|---|---|
committer | avg <avg@FreeBSD.org> | 2010-04-29 09:02:46 +0000 |
commit | cce2a4186b6b7e9dda2efd1770167b6c7b146c33 (patch) | |
tree | 8cd781d34426e9288b37f188e0079d59f20f3705 | |
parent | cbff4850b6fa646c25141877a2e0455c70564852 (diff) | |
download | FreeBSD-src-cce2a4186b6b7e9dda2efd1770167b6c7b146c33.zip FreeBSD-src-cce2a4186b6b7e9dda2efd1770167b6c7b146c33.tar.gz |
periodically save system time to hardware time-of-day clock
This is done in kern_ntptime, perhaps not the best place.
This is done using resettodr().
Some features:
- make save period configurable via tunable and sysctl
- period of zero disables saving, setting a non-zero period re-enables
it or reschedules it
- do saving only if system clock is ntp-synchronized
- save on shutdown
Discussed with: des, Peter Jeremy <peterjeremy@acm.org>
X-Maybe: save time near seconds boundary for better precision
MFC after: 2 weeks
-rw-r--r-- | sys/kern/kern_ntptime.c | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/sys/kern/kern_ntptime.c b/sys/kern/kern_ntptime.c index 9a4630f8..54c4b06b 100644 --- a/sys/kern/kern_ntptime.c +++ b/sys/kern/kern_ntptime.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> #include <sys/sysproto.h> +#include <sys/eventhandler.h> #include <sys/kernel.h> #include <sys/priv.h> #include <sys/proc.h> @@ -976,3 +977,67 @@ kern_adjtime(struct thread *td, struct timeval *delta, struct timeval *olddelta) return (0); } +static struct callout resettodr_callout; +static int resettodr_period = 1800; + +static void +periodic_resettodr(void *arg __unused) +{ + + if (!ntp_is_time_error()) { + mtx_lock(&Giant); + resettodr(); + mtx_unlock(&Giant); + } + if (resettodr_period > 0) + callout_schedule(&resettodr_callout, resettodr_period * hz); +} + +static void +shutdown_resettodr(void *arg __unused, int howto __unused) +{ + + callout_drain(&resettodr_callout); + if (resettodr_period > 0 && !ntp_is_time_error()) { + mtx_lock(&Giant); + resettodr(); + mtx_unlock(&Giant); + } +} + +static int +sysctl_resettodr_period(SYSCTL_HANDLER_ARGS) +{ + int error; + + error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); + if (error || !req->newptr) + return (error); + if (resettodr_period == 0) + callout_stop(&resettodr_callout); + else + callout_reset(&resettodr_callout, resettodr_period * hz, + periodic_resettodr, NULL); + return (0); +} + +SYSCTL_PROC(_machdep, OID_AUTO, rtc_save_period, CTLTYPE_INT|CTLFLAG_RW, + &resettodr_period, 1800, sysctl_resettodr_period, "I", + "Save system time to RTC with this period (in seconds)"); +TUNABLE_INT("machdep.rtc_save_period", &resettodr_period); + +static void +start_periodic_resettodr(void *arg __unused) +{ + + EVENTHANDLER_REGISTER(shutdown_pre_sync, shutdown_resettodr, NULL, + SHUTDOWN_PRI_FIRST); + callout_init(&resettodr_callout, 1); + if (resettodr_period == 0) + return; + callout_reset(&resettodr_callout, resettodr_period * hz, + periodic_resettodr, NULL); +} + +SYSINIT(periodic_resettodr, SI_SUB_RUN_SCHEDULER, SI_ORDER_ANY - 1, + start_periodic_resettodr, NULL); |