diff --git a/chrony.texi b/chrony.texi index f3d0c85..b867d21 100644 --- a/chrony.texi +++ b/chrony.texi @@ -1184,6 +1184,7 @@ directives can occur in any order in the file. * logchange directive:: Generate syslog messages if large offsets occur * logdir directive:: Specify directory for logging * mailonchange directive:: Send email if a clock correction above a threshold occurs +* makestep directive:: Step system clock if large correction is needed * manual directive:: Allow manual entry using chronyc's settime cmd. * maxupdateskew directive:: Stop bad estimates upsetting machine clock * noclientlog directive:: Prevent chronyd from gathering data about clients @@ -2085,6 +2086,32 @@ mailonchange root@@localhost 0.5 This would send a mail message to root if a change of more than 0.5 seconds were applied to the system clock. @c }}} +@c {{{ makestep +@node makestep directive +@subsection makestep +Normally chronyd will cause the system to gradually correct any time +offset, by slowing down or speeding up the clock as required. In +certain situations, the system clock may be so far adrift that this +slewing process would take a very long time to correct the system clock. + +This directive forces @code{chronyd} to step system clock if the +adjustment is larger than a threshold value, but only if there were no +more clock updates since @code{chronyd} was started than a specified +limit (a negative value can be used to disable the limit). + +This is particularly useful when using reference clocks, because the +@code{initstepslew} directive (@pxref{initstepslew directive}) works +only with NTP sources. + +An example of the use of this directive is + +@example +makestep 1000 10 +@end example + +This would step system clock if the adjustment is larger than 1000 +seconds, but only in the first ten clock updates. +@c }}} @c {{{ manual @node manual directive @subsection manual @@ -3075,6 +3102,10 @@ clock by the equivalent amount, making it correct immediately. BE WARNED - certain software will be seriously affected by such jumps to the system time. (That is the reason why chronyd uses slewing normally.) + +The @code{makestep} directive in the configuration file can be used +to step the clock automatically when the adjustment is larger than a +specified threshold, see @ref{makestep directive}. @c }}} @c {{{ manual @node manual command diff --git a/cmdmon.c b/cmdmon.c index e1edfba..397f6a3 100644 --- a/cmdmon.c +++ b/cmdmon.c @@ -1676,13 +1676,8 @@ handle_manual_delete(CMD_Request *rx_message, CMD_Reply *tx_message) static void handle_make_step(CMD_Request *rx_message, CMD_Reply *tx_message) { - int status; - status = LCL_MakeStep(); - if (status) { - tx_message->status = htons(STT_SUCCESS); - } else { - tx_message->status = htons(STT_NOTENABLED); - } + LCL_MakeStep(0.0); + tx_message->status = htons(STT_SUCCESS); return; } diff --git a/conf.c b/conf.c index 04cdab9..8cbc8b1 100644 --- a/conf.c +++ b/conf.c @@ -92,6 +92,7 @@ static void parse_cmdport(const char *); static void parse_rtconutc(const char *); static void parse_noclientlog(const char *); static void parse_clientloglimit(const char *); +static void parse_makestep(const char *); static void parse_logchange(const char *); static void parse_mailonchange(const char *); static void parse_bindaddress(const char *); @@ -146,6 +147,10 @@ static int enable_manual=0; incl. daylight saving). */ static int rtc_on_utc = 0; +/* Limit and threshold for clock stepping */ +static int make_step_limit = 0; +static double make_step_threshold = 0.0; + /* Flag set if we should log to syslog when a time adjustment exceeding the threshold is initiated */ static int do_log_change = 0; @@ -220,6 +225,7 @@ static const Command commands[] = { {"rtconutc", 8, parse_rtconutc}, {"noclientlog", 11, parse_noclientlog}, {"clientloglimit", 14, parse_clientloglimit}, + {"makestep", 8, parse_makestep}, {"logchange", 9, parse_logchange}, {"mailonchange", 12, parse_mailonchange}, {"bindaddress", 11, parse_bindaddress}, @@ -788,6 +794,19 @@ parse_clientloglimit(const char *line) /* ================================================== */ +static void +parse_makestep(const char *line) +{ + if (sscanf(line, "%lf %d", &make_step_threshold, &make_step_limit) != 2) { + make_step_limit = 0; + LOG(LOGS_WARN, LOGF_Configure, + "Could not read threshold or update limit for stepping clock at line %d\n", + line_number); + } +} + +/* ================================================== */ + static void parse_logchange(const char *line) { @@ -1319,6 +1338,15 @@ CNF_GetRTCOnUTC(void) /* ================================================== */ +void +CNF_GetMakeStep(int *limit, double *threshold) +{ + *limit = make_step_limit; + *threshold = make_step_threshold; +} + +/* ================================================== */ + void CNF_GetLogChange(int *enabled, double *threshold) { diff --git a/conf.h b/conf.h index 004bfcf..480bfed 100644 --- a/conf.h +++ b/conf.h @@ -60,6 +60,7 @@ extern int CNF_GetDumpOnExit(void); extern int CNF_GetManualEnabled(void); extern int CNF_GetCommandPort(void); extern int CNF_GetRTCOnUTC(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); extern int CNF_GetNoClientLog(void); diff --git a/local.c b/local.c index a1e95f5..0e69f5a 100644 --- a/local.c +++ b/local.c @@ -555,10 +555,10 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq, /* ================================================== */ /* Look at the current difference between the system time and the NTP - time, and make a step to cancel it. */ + time, and make a step to cancel it if it's larger than the threshold. */ int -LCL_MakeStep(void) +LCL_MakeStep(double threshold) { struct timeval raw; double correction; @@ -566,6 +566,9 @@ LCL_MakeStep(void) LCL_ReadRawTime(&raw); correction = LCL_GetOffsetCorrection(&raw); + if (fabs(correction) <= threshold) + return 0; + /* Cancel remaining slew and make the step */ LCL_AccumulateOffset(correction); LCL_ApplyStepOffset(-correction); diff --git a/local.h b/local.h index 6f7d211..98899a9 100644 --- a/local.h +++ b/local.h @@ -179,7 +179,7 @@ extern void LCL_Finalise(void); /* Routine to convert the outstanding system clock error to a step and apply it, e.g. if the system clock has ended up an hour wrong due to a timezone problem. */ -extern int LCL_MakeStep(void); +extern int LCL_MakeStep(double threshold); /* Routine to schedule a leap second. Leap second will be inserted at the end of the day if argument is positive, deleted if negative, diff --git a/reference.c b/reference.c index 2ac283c..af8baa1 100644 --- a/reference.c +++ b/reference.c @@ -61,6 +61,10 @@ static double max_update_skew; /* Flag indicating that we are initialised */ static int initialised = 0; +/* Threshold and update limit for stepping clock */ +static int make_step_limit; +static double make_step_threshold; + /* Flag and threshold for logging clock changes to syslog */ static int do_log_change; static double log_change_threshold; @@ -161,6 +165,7 @@ REF_Initialise(void) enable_local_stratum = CNF_AllowLocalReference(&local_stratum); + CNF_GetMakeStep(&make_step_limit, &make_step_threshold); CNF_GetLogChange(&do_log_change, &log_change_threshold); CNF_GetMailOnChange(&do_mail_change, &mail_change_threshold, &mail_change_user); @@ -318,6 +323,19 @@ maybe_log_offset(double offset) /* ================================================== */ +static void +maybe_make_step() +{ + if (make_step_limit == 0) { + return; + } else if (make_step_limit > 0) { + make_step_limit--; + } + LCL_MakeStep(make_step_threshold); +} + +/* ================================================== */ + static void update_leap_status(NTP_Leap leap) { @@ -487,6 +505,8 @@ REF_SetReference(int stratum, our_residual_freq = frequency; } + maybe_make_step(); + abs_freq_ppm = LCL_ReadAbsoluteFrequency(); write_log(ref_time, @@ -530,6 +550,7 @@ REF_SetManualReference maybe_log_offset(offset); LCL_AccumulateFrequencyAndOffset(frequency, offset); + maybe_make_step(); abs_freq_ppm = LCL_ReadAbsoluteFrequency();