1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-19 22:50:17 +03:00

Merge pull request #22789 from poettering/timesync-struct-log

timesyncd: various refactorings and cleanup + structured log msg on first sync
This commit is contained in:
Yu Watanabe 2022-03-21 02:26:59 +09:00 committed by GitHub
commit 59b8e67582
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 169 additions and 125 deletions

View File

@ -526,3 +526,11 @@ be updated to operate in a hotplug fashion without depending on
systemd-udev-settle.service:
@OFFENDING_UNITS@
-- 7c8a41f37b764941a0e1780b1be2f037
Subject: Initial clock synchronization
Defined-By: systemd
Support: %SUPPORT_URL%
For the first time during the current boot an NTP synchronization has been
acquired and the local system clock adjustment has been initiated.

View File

@ -39,6 +39,7 @@
#include "dirent-util.h"
#include "env-util.h"
#include "escape.h"
#include "event-util.h"
#include "exec-util.h"
#include "execute.h"
#include "exit-status.h"
@ -406,13 +407,8 @@ static int manager_setup_time_change(Manager *m) {
return 0;
m->time_change_event_source = sd_event_source_disable_unref(m->time_change_event_source);
m->time_change_fd = safe_close(m->time_change_fd);
m->time_change_fd = time_change_fd();
if (m->time_change_fd < 0)
return log_error_errno(m->time_change_fd, "Failed to create timer change timer fd: %m");
r = sd_event_add_io(m->event, &m->time_change_event_source, m->time_change_fd, EPOLLIN, manager_dispatch_time_change_fd, m);
r = event_add_time_change(m->event, &m->time_change_event_source, manager_dispatch_time_change_fd, m);
if (r < 0)
return log_error_errno(r, "Failed to create time change event source: %m");
@ -421,8 +417,6 @@ static int manager_setup_time_change(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to set priority of time change event sources: %m");
(void) sd_event_source_set_description(m->time_change_event_source, "manager-time-change");
log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd.");
return 0;
@ -820,7 +814,6 @@ int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager
.notify_fd = -1,
.cgroups_agent_fd = -1,
.signal_fd = -1,
.time_change_fd = -1,
.user_lookup_fds = { -1, -1 },
.private_listen_fd = -1,
.dev_autofs_fd = -1,
@ -1509,7 +1502,6 @@ Manager* manager_free(Manager *m) {
safe_close(m->signal_fd);
safe_close(m->notify_fd);
safe_close(m->cgroups_agent_fd);
safe_close(m->time_change_fd);
safe_close_pair(m->user_lookup_fds);
manager_close_ask_password(m);
@ -2913,7 +2905,6 @@ static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint
Unit *u;
assert(m);
assert(m->time_change_fd == fd);
log_struct(LOG_DEBUG,
"MESSAGE_ID=" SD_MESSAGE_TIME_CHANGE_STR,

View File

@ -226,7 +226,6 @@ struct Manager {
sd_event_source *sigchld_event_source;
int time_change_fd;
sd_event_source *time_change_event_source;
sd_event_source *timezone_change_event_source;

View File

@ -4,6 +4,7 @@
#include "event-source.h"
#include "event-util.h"
#include "fd-util.h"
#include "log.h"
#include "string-util.h"
@ -121,3 +122,41 @@ int event_source_is_enabled(sd_event_source *s) {
return sd_event_source_get_enabled(s, NULL);
}
int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handler_t callback, void *userdata) {
_cleanup_(sd_event_source_disable_unrefp) sd_event_source *s = NULL;
_cleanup_close_ int fd = -1;
int r;
assert(e);
/* Allocates an IO event source that gets woken up whenever the clock changes. Needs to be recreated on each event */
fd = time_change_fd();
if (fd < 0)
return fd;
r = sd_event_add_io(e, &s, fd, EPOLLIN, callback, userdata);
if (r < 0)
return r;
r = sd_event_source_set_io_fd_own(s, true);
if (r < 0)
return r;
TAKE_FD(fd);
r = sd_event_source_set_description(s, "time-change");
if (r < 0)
return r;
if (ret)
*ret = TAKE_PTR(s);
else {
r = sd_event_source_set_floating(s, true);
if (r < 0)
return r;
}
return 0;
}

View File

@ -29,3 +29,5 @@ int event_reset_time_relative(
bool force_reset);
int event_source_disable(sd_event_source *s);
int event_source_is_enabled(sd_event_source *s);
int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handler_t callback, void *userdata);

View File

@ -13,6 +13,7 @@
#include "bus-polkit.h"
#include "dirent-util.h"
#include "dns-domain.h"
#include "event-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "hostname-util.h"
@ -338,28 +339,16 @@ static int on_clock_change(sd_event_source *source, int fd, uint32_t revents, vo
}
static int manager_clock_change_listen(Manager *m) {
_cleanup_close_ int fd = -1;
int r;
assert(m);
m->clock_change_event_source = sd_event_source_disable_unref(m->clock_change_event_source);
fd = time_change_fd();
if (fd < 0)
return log_error_errno(fd, "Failed to allocate clock change timer fd: %m");
r = sd_event_add_io(m->event, &m->clock_change_event_source, fd, EPOLLIN, on_clock_change, m);
r = event_add_time_change(m->event, &m->clock_change_event_source, on_clock_change, m);
if (r < 0)
return log_error_errno(r, "Failed to create clock change event source: %m");
r = sd_event_source_set_io_fd_own(m->clock_change_event_source, true);
if (r < 0)
return log_error_errno(r, "Failed to pass ownership of clock fd to event source: %m");
TAKE_FD(fd);
(void) sd_event_source_set_description(m->clock_change_event_source, "clock-change");
return 0;
}

View File

@ -200,6 +200,9 @@ _SD_BEGIN_DECLARATIONS;
#define SD_MESSAGE_SYSTEMD_UDEV_SETTLE_DEPRECATED_STR \
SD_ID128_MAKE_STR(1c,04,54,c1,bd,22,41,e0,ac,6f,ef,b4,bc,63,14,33)
#define SD_MESSAGE_TIME_SYNC SD_ID128_MAKE(7c,8a,41,f3,7b,76,49,41,a0,e1,78,0b,1b,e2,f0,37)
#define SD_MESSAGE_TIME_SYNC_STR SD_ID128_MAKE_STR(7c,8a,41,f3,7b,76,49,41,a0,e1,78,0b,1b,e2,f0,37)
_SD_END_DECLARATIONS;
#endif

View File

@ -11,9 +11,11 @@
#include <sys/types.h>
#include "sd-daemon.h"
#include "sd-messages.h"
#include "alloc-util.h"
#include "dns-domain.h"
#include "event-util.h"
#include "fd-util.h"
#include "format-util.h"
#include "fs-util.h"
@ -28,6 +30,7 @@
#include "time-util.h"
#include "timesyncd-conf.h"
#include "timesyncd-manager.h"
#include "user-util.h"
#include "util.h"
#ifndef ADJ_SETOFFSET
@ -59,7 +62,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 int manager_save_time_and_rearm(Manager *m, usec_t t);
static double ntp_ts_short_to_d(const struct ntp_ts_short *ts) {
return be16toh(ts->sec) + (be16toh(ts->frac) / 65536.0);
@ -229,14 +232,9 @@ static int manager_clock_watch_setup(Manager *m) {
assert(m);
m->event_clock_watch = sd_event_source_unref(m->event_clock_watch);
safe_close(m->clock_watch_fd);
m->event_clock_watch = sd_event_source_disable_unref(m->event_clock_watch);
m->clock_watch_fd = time_change_fd();
if (m->clock_watch_fd < 0)
return log_error_errno(m->clock_watch_fd, "Failed to create timerfd: %m");
r = sd_event_add_io(m->event, &m->event_clock_watch, m->clock_watch_fd, EPOLLIN, manager_clock_watch, m);
r = event_add_time_change(m->event, &m->event_clock_watch, manager_clock_watch, m);
if (r < 0)
return log_error_errno(r, "Failed to create clock watch event source: %m");
@ -244,31 +242,29 @@ static int manager_clock_watch_setup(Manager *m) {
}
static int manager_adjust_clock(Manager *m, double offset, int leap_sec) {
struct timex tmx = {};
int r;
struct timex tmx;
assert(m);
/*
* For small deltas, tell the kernel to gradually adjust the system
* clock to the NTP time, larger deltas are just directly set.
*/
/* For small deltas, tell the kernel to gradually adjust the system clock to the NTP time, larger
* deltas are just directly set. */
if (fabs(offset) < NTP_MAX_ADJUST) {
tmx.modes = ADJ_STATUS | ADJ_NANO | ADJ_OFFSET | ADJ_TIMECONST | ADJ_MAXERROR | ADJ_ESTERROR;
tmx.status = STA_PLL;
tmx.offset = offset * NSEC_PER_SEC;
tmx.constant = log2i(m->poll_interval_usec / USEC_PER_SEC) - 4;
tmx.maxerror = 0;
tmx.esterror = 0;
tmx = (struct timex) {
.modes = ADJ_STATUS | ADJ_NANO | ADJ_OFFSET | ADJ_TIMECONST | ADJ_MAXERROR | ADJ_ESTERROR,
.status = STA_PLL,
.offset = offset * NSEC_PER_SEC,
.constant = log2i(m->poll_interval_usec / USEC_PER_SEC) - 4,
};
log_debug(" adjust (slew): %+.3f sec", offset);
} else {
tmx.modes = ADJ_STATUS | ADJ_NANO | ADJ_SETOFFSET | ADJ_MAXERROR | ADJ_ESTERROR;
tmx = (struct timex) {
.modes = ADJ_STATUS | ADJ_NANO | ADJ_SETOFFSET | ADJ_MAXERROR | ADJ_ESTERROR,
/* ADJ_NANO uses nanoseconds in the microseconds field */
tmx.time.tv_sec = (long)offset;
tmx.time.tv_usec = (offset - tmx.time.tv_sec) * NSEC_PER_SEC;
tmx.maxerror = 0;
tmx.esterror = 0;
/* ADJ_NANO uses nanoseconds in the microseconds field */
.time.tv_sec = (long)offset,
.time.tv_usec = (offset - (double) (long) offset) * NSEC_PER_SEC,
};
/* the kernel expects -0.3s as {-1, 7000.000.000} */
if (tmx.time.tv_usec < 0) {
@ -280,14 +276,11 @@ static int manager_adjust_clock(Manager *m, double offset, int leap_sec) {
log_debug(" adjust (jump): %+.3f sec", offset);
}
/*
* An unset STA_UNSYNC will enable the kernel's 11-minute mode,
* which syncs the system time periodically to the RTC.
/* An unset STA_UNSYNC will enable the kernel's 11-minute mode, which syncs the system time
* periodically to the RTC.
*
* In case the RTC runs in local time, never touch the RTC,
* we have no way to properly handle daylight saving changes and
* mobile devices moving between time zones.
*/
* In case the RTC runs in local time, never touch the RTC, we have no way to properly handle
* daylight saving changes and mobile devices moving between time zones. */
if (m->rtc_local_time)
tmx.status |= STA_UNSYNC;
@ -300,17 +293,9 @@ static int manager_adjust_clock(Manager *m, double offset, int leap_sec) {
break;
}
r = clock_adjtime(CLOCK_REALTIME, &tmx);
if (r < 0)
if (clock_adjtime(CLOCK_REALTIME, &tmx) < 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("/run/systemd/timesync/synchronized");
m->drift_freq = tmx.freq;
log_debug(" status : %04i %s\n"
@ -427,15 +412,12 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
.msg_name = &server_addr,
.msg_namelen = sizeof(server_addr),
};
struct cmsghdr *cmsg;
struct timespec *recv_time = NULL;
triple_timestamp dts;
ssize_t len;
double origin, receive, trans, dest;
double delay, offset;
double root_distance;
double origin, receive, trans, dest, delay, offset, root_distance;
bool spike;
int leap_sec;
int r;
int leap_sec, r;
assert(source);
assert(m);
@ -466,21 +448,9 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
return 0;
}
CMSG_FOREACH(cmsg, &msghdr) {
if (cmsg->cmsg_level != SOL_SOCKET)
continue;
switch (cmsg->cmsg_type) {
case SCM_TIMESTAMPNS:
assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct timespec)));
recv_time = (struct timespec *) CMSG_DATA(cmsg);
break;
}
}
recv_time = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_TIMESTAMPNS, struct timespec);
if (!recv_time)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid packet timestamp.");
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Packet timestamp missing.");
if (!m->pending) {
log_debug("Unexpected reply. Ignoring.");
@ -597,10 +567,23 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
m->samples_jitter, spike ? " spike" : "",
m->poll_interval_usec / USEC_PER_SEC);
/* Get current monotonic/realtime clocks immediately before adjusting the latter */
triple_timestamp_get(&dts);
if (!spike) {
/* Fix up our idea of the time. */
dts.realtime = (usec_t) (dts.realtime + offset * USEC_PER_SEC);
r = manager_adjust_clock(m, offset, leap_sec);
if (r < 0)
log_error_errno(r, "Failed to call clock_adjtime(): %m");
(void) manager_save_time_and_rearm(m, dts.realtime);
/* If touch fails, there isn't much we can do. Maybe it'll work next time. */
r = touch("/run/systemd/timesync/synchronized");
if (r < 0)
log_debug_errno(r, "Failed to touch /run/systemd/timesync/synchronized, ignoring: %m");
}
/* Save NTP response */
@ -621,15 +604,26 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
"NTPMessage",
NULL);
if (!m->good) {
if (!m->talking) {
_cleanup_free_ char *pretty = NULL;
m->good = true;
m->talking = true;
server_address_pretty(m->current_server_address, &pretty);
/* "Initial", as further successful syncs will not be logged. */
log_info("Initial synchronization to time server %s (%s).", strna(pretty), m->current_server_name->string);
sd_notifyf(false, "STATUS=Initial synchronization to time server %s (%s).", strna(pretty), m->current_server_name->string);
(void) server_address_pretty(m->current_server_address, &pretty);
log_info("Contacted time server %s (%s).", strna(pretty), m->current_server_name->string);
(void) sd_notifyf(false, "STATUS=Contacted time server %s (%s).", strna(pretty), m->current_server_name->string);
}
if (!spike && !m->synchronized) {
m->synchronized = true;
log_struct(LOG_INFO,
LOG_MESSAGE("Initial clock synchronization to %s.", FORMAT_TIMESTAMP_STYLE(dts.realtime, TIMESTAMP_US)),
"MESSAGE_ID=" SD_MESSAGE_TIME_SYNC_STR,
"MONOTONIC_USEC=" USEC_FMT, dts.monotonic,
"REALTIME_USEC=" USEC_FMT, dts.realtime,
"BOOTIME_USEC=" USEC_FMT, dts.boottime);
}
r = manager_arm_timer(m, m->poll_interval_usec);
@ -686,14 +680,14 @@ static int manager_begin(Manager *m) {
assert_return(m->current_server_name, -EHOSTUNREACH);
assert_return(m->current_server_address, -EHOSTUNREACH);
m->good = false;
m->talking = false;
m->missed_replies = NTP_MAX_MISSED_REPLIES;
if (m->poll_interval_usec == 0)
m->poll_interval_usec = m->poll_interval_min_usec;
server_address_pretty(m->current_server_address, &pretty);
log_debug("Connecting to time server %s (%s).", strna(pretty), m->current_server_name->string);
sd_notifyf(false, "STATUS=Connecting to time server %s (%s).", strna(pretty), m->current_server_name->string);
(void) sd_notifyf(false, "STATUS=Connecting to time server %s (%s).", strna(pretty), m->current_server_name->string);
r = manager_clock_watch_setup(m);
if (r < 0)
@ -818,7 +812,7 @@ int manager_connect(Manager *m) {
if (m->current_server_address && m->current_server_address->addresses_next)
manager_set_server_address(m, m->current_server_address->addresses_next);
else {
struct addrinfo hints = {
static const struct addrinfo hints = {
.ai_flags = AI_NUMERICSERV|AI_ADDRCONFIG,
.ai_socktype = SOCK_DGRAM,
};
@ -910,12 +904,11 @@ void manager_disconnect(Manager *m) {
manager_listen_stop(m);
m->event_clock_watch = sd_event_source_unref(m->event_clock_watch);
m->clock_watch_fd = safe_close(m->clock_watch_fd);
m->event_clock_watch = sd_event_source_disable_unref(m->event_clock_watch);
m->event_timeout = sd_event_source_unref(m->event_timeout);
sd_notify(false, "STATUS=Idle.");
(void) sd_notify(false, "STATUS=Idle.");
}
void manager_flush_server_names(Manager *m, ServerType t) {
@ -1098,21 +1091,26 @@ int manager_new(Manager **ret) {
assert(ret);
m = new0(Manager, 1);
m = new(Manager, 1);
if (!m)
return -ENOMEM;
m->root_distance_max_usec = NTP_ROOT_DISTANCE_MAX_USEC;
m->poll_interval_min_usec = NTP_POLL_INTERVAL_MIN_USEC;
m->poll_interval_max_usec = NTP_POLL_INTERVAL_MAX_USEC;
*m = (Manager) {
.root_distance_max_usec = NTP_ROOT_DISTANCE_MAX_USEC,
.poll_interval_min_usec = NTP_POLL_INTERVAL_MIN_USEC,
.poll_interval_max_usec = NTP_POLL_INTERVAL_MAX_USEC,
m->connection_retry_usec = DEFAULT_CONNECTION_RETRY_USEC;
.connection_retry_usec = DEFAULT_CONNECTION_RETRY_USEC,
m->server_socket = m->clock_watch_fd = -1;
.server_socket = -1,
m->ratelimit = (RateLimit) { RATELIMIT_INTERVAL_USEC, RATELIMIT_BURST };
.ratelimit = (RateLimit) {
RATELIMIT_INTERVAL_USEC,
RATELIMIT_BURST
},
m->save_time_interval_usec = DEFAULT_SAVE_TIME_INTERVAL_USEC;
.save_time_interval_usec = DEFAULT_SAVE_TIME_INTERVAL_USEC,
};
r = sd_event_default(&m->event);
if (r < 0)
@ -1123,6 +1121,12 @@ int manager_new(Manager **ret) {
(void) sd_event_set_watchdog(m->event, true);
/* Load previous synchronization state */
r = access("/run/systemd/timesync/synchronized", F_OK);
if (r < 0 && errno != ENOENT)
log_debug_errno(errno, "Failed to determine whether /run/systemd/timesync/synchronized exists, ignoring: %m");
m->synchronized = r >= 0;
r = sd_resolve_default(&m->resolve);
if (r < 0)
return r;
@ -1147,7 +1151,7 @@ static int manager_save_time_handler(sd_event_source *s, uint64_t usec, void *us
assert(m);
(void) manager_save_time_and_rearm(m);
(void) manager_save_time_and_rearm(m, USEC_INFINITY);
return 0;
}
@ -1175,12 +1179,16 @@ int manager_setup_save_time_event(Manager *m) {
return 0;
}
static int manager_save_time_and_rearm(Manager *m) {
static int manager_save_time_and_rearm(Manager *m, usec_t t) {
int r;
assert(m);
r = touch(CLOCK_FILE);
/* Updates the timestamp file to the specified time. If 't' is USEC_INFINITY uses the current system
* clock, but otherwise uses the specified timestamp. Note that whenever we acquire an NTP sync the
* specified timestamp value might be more accurate than the system clock, since the latter is
* subject to slow adjustments. */
r = touch_file(CLOCK_FILE, false, t, UID_INVALID, GID_INVALID, MODE_INVALID);
if (r < 0)
log_debug_errno(r, "Failed to update " CLOCK_FILE ", ignoring: %m");

View File

@ -61,7 +61,7 @@ struct Manager {
int missed_replies;
uint64_t packet_count;
sd_event_source *event_timeout;
bool good;
bool talking;
/* last sent packet */
struct timespec trans_time_mon;
@ -92,7 +92,6 @@ struct Manager {
/* watch for time changes */
sd_event_source *event_clock_watch;
int clock_watch_fd;
/* Retry connections */
sd_event_source *event_retry;
@ -105,6 +104,9 @@ struct Manager {
struct timespec origin_time, dest_time;
bool spike;
/* Indicates whether we ever managed to set the local clock from NTP */
bool synchronized;
/* save time event */
sd_event_source *event_save_time;
usec_t save_time_interval_usec;

View File

@ -16,16 +16,19 @@ int server_address_new(
assert(socklen >= offsetof(struct sockaddr, sa_data));
assert(socklen <= sizeof(union sockaddr_union));
a = new0(ServerAddress, 1);
a = new(ServerAddress, 1);
if (!a)
return -ENOMEM;
*a = (ServerAddress) {
.name = n,
.socklen = socklen,
};
memcpy(&a->sockaddr, sockaddr, socklen);
a->socklen = socklen;
LIST_FIND_TAIL(addresses, n->addresses, tail);
LIST_INSERT_AFTER(addresses, n->addresses, tail, a);
a->name = n;
if (ret)
*ret = a;
@ -58,12 +61,16 @@ int server_name_new(
assert(m);
assert(string);
n = new0(ServerName, 1);
n = new(ServerName, 1);
if (!n)
return -ENOMEM;
n->type = type;
n->string = strdup(string);
*n = (ServerName) {
.manager = m,
.type = type,
.string = strdup(string),
};
if (!n->string) {
free(n);
return -ENOMEM;
@ -81,8 +88,6 @@ int server_name_new(
} else
assert_not_reached();
n->manager = m;
if (type != SERVER_FALLBACK &&
m->current_server_name &&
m->current_server_name->type == SERVER_FALLBACK)

View File

@ -22,9 +22,8 @@
#include "user-util.h"
static int load_clock_timestamp(uid_t uid, gid_t gid) {
usec_t min = TIME_EPOCH * USEC_PER_SEC, ct;
_cleanup_close_ int fd = -1;
usec_t min = TIME_EPOCH * USEC_PER_SEC;
usec_t ct;
int r;
/* Let's try to make sure that the clock is always
@ -40,8 +39,7 @@ static int load_clock_timestamp(uid_t uid, gid_t gid) {
usec_t stamp;
/* check if the recorded time is later than the compiled-in one */
r = fstat(fd, &st);
if (r >= 0) {
if (fstat(fd, &st) >= 0) {
stamp = timespec_load(&st.st_mtim);
if (stamp > min)
min = stamp;
@ -64,7 +62,7 @@ static int load_clock_timestamp(uid_t uid, gid_t gid) {
}
/* create stamp file with the compiled-in date */
r = touch_file(CLOCK_FILE, false, min, uid, gid, 0644);
r = touch_file(CLOCK_FILE, /* parents= */ false, min, uid, gid, 0644);
if (r < 0)
log_debug_errno(r, "Failed to create %s, ignoring: %m", CLOCK_FILE);
}