diff --git a/chrony.texi b/chrony.texi index f9980f1..af8e123 100644 --- a/chrony.texi +++ b/chrony.texi @@ -1197,6 +1197,7 @@ directives can occur in any order in the file. * rtcdevice directive:: Specify name of enhanced RTC device (if not /dev/rtc) * rtcfile directive:: Specify the file where real-time clock data is stored * rtconutc directive:: Specify that the real time clock keeps UTC not local time +* rtcsync directive:: Specify that RTC should be automatically synchronised by kernel * server directive:: Specify an NTP server * sched_priority directive:: Require real-time scheduling and specify a priority for it. * lock_all directive:: Require that chronyd be locked into RAM. @@ -2458,6 +2459,17 @@ If the @code{rtconutc} directive appears, it means the RTC is required to keep UTC. The directive takes no arguments. It is equivalent to specifying the @code{-u} switch to the Linux @file{/sbin/clock} program. @c }}} +@c {{{ rtcsync +@node rtcsync directive +@subsection rtcsync + +The @code{rtcsync} directive will enable a kernel mode where the +system time is copied to the real time clock (RTC) every 11 minutes. + +This directive is supported only on Linux and cannot be used when the +normal RTC tracking is enabled, i.e. when the @code{rtcfile} directive +is used. +@c }}} @c {{{ sched_priority @node sched_priority directive @subsection sched_priority diff --git a/chrony_timex.h b/chrony_timex.h index 38e1146..6b8027b 100644 --- a/chrony_timex.h +++ b/chrony_timex.h @@ -36,6 +36,7 @@ struct timex { }; #define ADJ_FREQUENCY 0x0002 /* frequency offset */ +#define ADJ_MAXERROR 0x0004 /* maximum time error */ #define ADJ_STATUS 0x0010 /* clock status */ #define ADJ_TICK 0x4000 /* tick value */ #define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */ diff --git a/conf.c b/conf.c index 1556c2f..d1dd2ed 100644 --- a/conf.c +++ b/conf.c @@ -90,6 +90,7 @@ static void parse_cmdallow(const char *); static void parse_cmddeny(const char *); static void parse_cmdport(const char *); static void parse_rtconutc(const char *); +static void parse_rtcsync(const char *); static void parse_noclientlog(const char *); static void parse_clientloglimit(const char *); static void parse_fallbackdrift(const char *); @@ -150,6 +151,9 @@ static int enable_manual=0; incl. daylight saving). */ static int rtc_on_utc = 0; +/* Flag set if the RTC should be automatically synchronised by kernel */ +static int rtc_sync = 0; + /* Limit and threshold for clock stepping */ static int make_step_limit = 0; static double make_step_threshold = 0.0; @@ -235,6 +239,7 @@ static const Command commands[] = { {"cmddeny", 7, parse_cmddeny}, {"cmdport", 7, parse_cmdport}, {"rtconutc", 8, parse_rtconutc}, + {"rtcsync", 7, parse_rtcsync}, {"noclientlog", 11, parse_noclientlog}, {"clientloglimit", 14, parse_clientloglimit}, {"fallbackdrift", 13, parse_fallbackdrift}, @@ -784,6 +789,14 @@ parse_rtconutc(const char *line) /* ================================================== */ +static void +parse_rtcsync(const char *line) +{ + rtc_sync = 1; +} + +/* ================================================== */ + static void parse_noclientlog(const char *line) { @@ -1394,6 +1407,14 @@ CNF_GetRTCOnUTC(void) /* ================================================== */ +int +CNF_GetRTCSync(void) +{ + return rtc_sync; +} + +/* ================================================== */ + void CNF_GetMakeStep(int *limit, double *threshold) { diff --git a/conf.h b/conf.h index 31f4cf0..cf8788b 100644 --- a/conf.h +++ b/conf.h @@ -61,6 +61,7 @@ extern int CNF_GetDumpOnExit(void); extern int CNF_GetManualEnabled(void); extern int CNF_GetCommandPort(void); extern int CNF_GetRTCOnUTC(void); +extern int CNF_GetRTCSync(void); extern void CNF_GetMakeStep(int *limit, double *threshold); extern void CNF_GetLogChange(int *enabled, double *threshold); extern void CNF_GetMailOnChange(int *enabled, double *threshold, char **user); diff --git a/rtc.c b/rtc.c index d4ec01e..688c238 100644 --- a/rtc.c +++ b/rtc.c @@ -86,6 +86,10 @@ RTC_Initialise(void) file_name = CNF_GetRtcFile(); if (file_name) { + if (CNF_GetRTCSync()) { + LOG_FATAL(LOGF_Rtc, "rtcfile directive cannot be used with rtcsync"); + } + if (driver.init) { if ((driver.init)()) { ok = 1; diff --git a/sys_linux.c b/sys_linux.c index 11cf6a4..c40e99c 100644 --- a/sys_linux.c +++ b/sys_linux.c @@ -991,6 +991,8 @@ SYS_Linux_Initialise(void) lcl_RegisterSystemDrivers(read_frequency, set_frequency, accrue_offset, apply_step_offset, get_offset_correction, set_leap); + + TMX_SetSync(CNF_GetRTCSync()); } /* ================================================== */ diff --git a/wrap_adjtimex.c b/wrap_adjtimex.c index 13a4440..f34f477 100644 --- a/wrap_adjtimex.c +++ b/wrap_adjtimex.c @@ -39,8 +39,7 @@ #include "chrony_timex.h" #include "wrap_adjtimex.h" -/* Save leap status between calls */ -static int leap_status = 0; +static int status = 0; int TMX_SetTick(long tick) @@ -75,9 +74,16 @@ TMX_SetFrequency(double *freq, long tick) txc.freq = (long)(*freq * (double)(1 << SHIFT_USEC)); *freq = txc.freq / (double)(1 << SHIFT_USEC); txc.tick = tick; - txc.status = STA_UNSYNC; /* Prevent any of the FLL/PLL stuff coming - up */ - txc.status |= leap_status; /* Preserve leap bits */ + + /* Prevent any of the FLL/PLL stuff coming up */ + txc.status = status; + + if (!(status & STA_UNSYNC)) { + /* maxerror has to be reset periodically to prevent kernel + from enabling UNSYNC flag */ + txc.modes |= ADJ_MAXERROR; + txc.maxerror = 0; + } return adjtimex(&txc); } @@ -165,16 +171,32 @@ TMX_SetLeap(int leap) { struct timex txc; + status &= ~(STA_INS | STA_DEL); + if (leap > 0) { - leap_status = STA_INS; + status |= STA_INS; } else if (leap < 0) { - leap_status = STA_DEL; - } else { - leap_status = 0; + status |= STA_DEL; } txc.modes = ADJ_STATUS; - txc.status = STA_UNSYNC | leap_status; + txc.status = status; + + return adjtimex(&txc); +} + +int TMX_SetSync(int sync) +{ + struct timex txc; + + if (sync) { + status &= ~STA_UNSYNC; + } else { + status |= STA_UNSYNC; + } + + txc.modes = ADJ_STATUS; + txc.status = status; return adjtimex(&txc); } diff --git a/wrap_adjtimex.h b/wrap_adjtimex.h index f88188a..45c79de 100644 --- a/wrap_adjtimex.h +++ b/wrap_adjtimex.h @@ -76,6 +76,7 @@ int TMX_GetOffsetLeftOld(long *offset); int TMX_GetOffsetLeft(long *offset); int TMX_ReadCurrentParams(struct tmx_params *params); int TMX_SetLeap(int leap); +int TMX_SetSync(int sync); #endif /* GOT_WRAP_ADJTIMEX_H */