mirror of
https://github.com/systemd/systemd.git
synced 2024-11-23 10:13:34 +08:00
timesync: add option to periodically save time
This commit is contained in:
parent
8a513eee30
commit
33e82f3ef3
@ -75,10 +75,11 @@
|
||||
<term><filename>/var/lib/systemd/timesync/clock</filename></term>
|
||||
|
||||
<listitem>
|
||||
<para>The modification time ("mtime") of this file indicates the timestamp of the last successful
|
||||
synchronization (or at least the systemd build date, in case synchronization was not possible). It
|
||||
is used to ensure that the system clock remains roughly monotonic across reboots, in case no local
|
||||
RTC is available.</para>
|
||||
<para>The modification time ("mtime") of this file is updated on each successful NTP synchronization
|
||||
or after each <varname>SaveIntervalSec=</varname> time interval, as specified in
|
||||
<citerefentry><refentrytitle>timesyncd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||
At the minimum, it will be set to the systemd build date. It is used to ensure that the system clock
|
||||
remains roughly monotonic across reboots, in case no local RTC is available.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -103,6 +103,18 @@
|
||||
Defaults to 30 seconds and must not be smaller than 1 second.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>SaveIntervalSec=</varname></term>
|
||||
<listitem><para>The interval at which the current time is periodically saved to disk, in the absence
|
||||
of any recent synchronisation from an NTP server. This is especially useful for offline systems
|
||||
with no local RTC, as it will guarantee that the system clock remains roughly monotonic across
|
||||
reboots.</para>
|
||||
|
||||
<para>Takes a time interval value. The default unit is seconds, but other units may be specified, see
|
||||
<citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||
Defaults to 60 seconds.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -25,3 +25,4 @@ Time.RootDistanceMaxSec, config_parse_sec, 0, offs
|
||||
Time.PollIntervalMinSec, config_parse_sec, 0, offsetof(Manager, poll_interval_min_usec)
|
||||
Time.PollIntervalMaxSec, config_parse_sec, 0, offsetof(Manager, poll_interval_max_usec)
|
||||
Time.ConnectionRetrySec, config_parse_sec, 0, offsetof(Manager, connection_retry_usec)
|
||||
Time.SaveIntervalSec, config_parse_sec, 0, offsetof(Manager, save_time_interval_usec)
|
||||
|
@ -59,6 +59,7 @@ static int manager_arm_timer(Manager *m, usec_t next);
|
||||
static int manager_clock_watch_setup(Manager *m);
|
||||
static int manager_listen_setup(Manager *m);
|
||||
static void manager_listen_stop(Manager *m);
|
||||
static int manager_save_time_and_rearm(Manager *m);
|
||||
|
||||
static double ntp_ts_short_to_d(const struct ntp_ts_short *ts) {
|
||||
return be16toh(ts->sec) + (be16toh(ts->frac) / 65536.0);
|
||||
@ -303,8 +304,11 @@ static int manager_adjust_clock(Manager *m, double offset, int leap_sec) {
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = manager_save_time_and_rearm(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* If touch fails, there isn't much we can do. Maybe it'll work next time. */
|
||||
(void) touch("/var/lib/systemd/timesync/clock");
|
||||
(void) touch("/run/systemd/timesync/synchronized");
|
||||
|
||||
m->drift_freq = tmx.freq;
|
||||
@ -591,7 +595,6 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
|
||||
m->poll_interval_usec / USEC_PER_SEC);
|
||||
|
||||
if (!spike) {
|
||||
m->sync = true;
|
||||
r = manager_adjust_clock(m, offset, leap_sec);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to call clock_adjtime(): %m");
|
||||
@ -942,6 +945,8 @@ Manager* manager_free(Manager *m) {
|
||||
sd_event_source_unref(m->network_event_source);
|
||||
sd_network_monitor_unref(m->network_monitor);
|
||||
|
||||
sd_event_source_unref(m->event_save_time);
|
||||
|
||||
sd_resolve_unref(m->resolve);
|
||||
sd_event_unref(m->event);
|
||||
|
||||
@ -1104,6 +1109,8 @@ int manager_new(Manager **ret) {
|
||||
|
||||
m->ratelimit = (RateLimit) { RATELIMIT_INTERVAL_USEC, RATELIMIT_BURST };
|
||||
|
||||
m->save_time_interval_usec = DEFAULT_SAVE_TIME_INTERVAL_USEC;
|
||||
|
||||
r = sd_event_default(&m->event);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -1131,3 +1138,60 @@ int manager_new(Manager **ret) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int manager_save_time_handler(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
Manager *m = userdata;
|
||||
|
||||
assert(m);
|
||||
|
||||
(void) manager_save_time_and_rearm(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_setup_save_time_event(Manager *m) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(!m->event_save_time);
|
||||
|
||||
if (m->save_time_interval_usec == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
/* NB: we'll accumulate scheduling latencies here, but this doesn't matter */
|
||||
r = sd_event_add_time_relative(
|
||||
m->event, &m->event_save_time,
|
||||
clock_boottime_or_monotonic(),
|
||||
m->save_time_interval_usec,
|
||||
10 * USEC_PER_SEC,
|
||||
manager_save_time_handler, m);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add save time event: %m");
|
||||
|
||||
(void) sd_event_source_set_description(m->event_save_time, "save-time");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int manager_save_time_and_rearm(Manager *m) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
r = touch(CLOCK_FILE);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to update " CLOCK_FILE ", ignoring: %m");
|
||||
|
||||
m->save_on_exit = true;
|
||||
|
||||
if (m->save_time_interval_usec != USEC_INFINITY) {
|
||||
r = sd_event_source_set_time_relative(m->event_save_time, m->save_time_interval_usec);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to rearm save time event: %m");
|
||||
|
||||
r = sd_event_source_set_enabled(m->event_save_time, SD_EVENT_ONESHOT);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enable save time event: %m");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -27,7 +27,12 @@ typedef struct Manager Manager;
|
||||
#define NTP_RETRY_INTERVAL_MIN_USEC (15 * USEC_PER_SEC)
|
||||
#define NTP_RETRY_INTERVAL_MAX_USEC (6 * 60 * USEC_PER_SEC) /* 6 minutes */
|
||||
|
||||
#define DEFAULT_CONNECTION_RETRY_USEC (30*USEC_PER_SEC)
|
||||
#define DEFAULT_CONNECTION_RETRY_USEC (30 * USEC_PER_SEC)
|
||||
|
||||
#define DEFAULT_SAVE_TIME_INTERVAL_USEC (60 * USEC_PER_SEC)
|
||||
|
||||
#define STATE_DIR "/var/lib/systemd/timesync"
|
||||
#define CLOCK_FILE STATE_DIR "/clock"
|
||||
|
||||
struct Manager {
|
||||
sd_bus *bus;
|
||||
@ -83,7 +88,6 @@ struct Manager {
|
||||
|
||||
/* last change */
|
||||
bool jumped;
|
||||
bool sync;
|
||||
int64_t drift_freq;
|
||||
|
||||
/* watch for time changes */
|
||||
@ -100,6 +104,11 @@ struct Manager {
|
||||
struct ntp_msg ntpmsg;
|
||||
struct timespec origin_time, dest_time;
|
||||
bool spike;
|
||||
|
||||
/* save time event */
|
||||
sd_event_source *event_save_time;
|
||||
usec_t save_time_interval_usec;
|
||||
bool save_on_exit;
|
||||
};
|
||||
|
||||
int manager_new(Manager **ret);
|
||||
@ -113,3 +122,5 @@ void manager_flush_server_names(Manager *m, ServerType t);
|
||||
|
||||
int manager_connect(Manager *m);
|
||||
void manager_disconnect(Manager *m);
|
||||
|
||||
int manager_setup_save_time_event(Manager *m);
|
||||
|
@ -21,9 +21,6 @@
|
||||
#include "timesyncd-manager.h"
|
||||
#include "user-util.h"
|
||||
|
||||
#define STATE_DIR "/var/lib/systemd/timesync"
|
||||
#define CLOCK_FILE STATE_DIR "/clock"
|
||||
|
||||
static int load_clock_timestamp(uid_t uid, gid_t gid) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
usec_t min = TIME_EPOCH * USEC_PER_SEC;
|
||||
@ -155,6 +152,10 @@ static int run(int argc, char *argv[]) {
|
||||
"STATUS=Daemon is running",
|
||||
NOTIFY_STOPPING);
|
||||
|
||||
r = manager_setup_save_time_event(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (network_is_online()) {
|
||||
r = manager_connect(m);
|
||||
if (r < 0)
|
||||
@ -166,10 +167,10 @@ static int run(int argc, char *argv[]) {
|
||||
return log_error_errno(r, "Failed to run event loop: %m");
|
||||
|
||||
/* if we got an authoritative time, store it in the file system */
|
||||
if (m->sync) {
|
||||
if (m->save_on_exit) {
|
||||
r = touch(CLOCK_FILE);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to touch %s, ignoring: %m", CLOCK_FILE);
|
||||
log_debug_errno(r, "Failed to touch " CLOCK_FILE ", ignoring: %m");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -18,3 +18,4 @@
|
||||
#RootDistanceMaxSec=5
|
||||
#PollIntervalMinSec=32
|
||||
#PollIntervalMaxSec=2048
|
||||
#SaveIntervalSec=60
|
||||
|
Loading…
Reference in New Issue
Block a user