Introduce sd_notify_barrier
This adds the sd_notify_barrier function, to allow users to synchronize against the reception of sd_notify(3) status messages. It acts as a synchronization point, and a successful return gurantees that all previous messages have been consumed by the manager. This can be used to eliminate race conditions where the sending process exits too early for systemd to associate its PID to a cgroup and attribute the status message to a unit correctly. systemd-notify now uses this function for proper notification delivery and be useful for NotifyAccess=all units again in user mode, or in cases where it doesn't have a control process as parent. Fixes: #2739
This commit is contained in:
@@ -2284,6 +2284,20 @@ static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, ui
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool manager_process_barrier_fd(const char *buf, FDSet *fds) {
|
||||
assert(buf);
|
||||
|
||||
/* nothing else must be sent when using BARRIER=1 */
|
||||
if (STR_IN_SET(buf, "BARRIER=1", "BARRIER=1\n")) {
|
||||
if (fdset_size(fds) != 1)
|
||||
log_warning("Got incorrect number of fds with BARRIER=1, closing them.");
|
||||
return true;
|
||||
} else if (startswith(buf, "BARRIER=1\n") || strstr(buf, "\nBARRIER=1\n") || endswith(buf, "\nBARRIER=1"))
|
||||
log_warning("Extra notification messages sent with BARRIER=1, ignoring everything.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void manager_invoke_notify_message(
|
||||
Manager *m,
|
||||
Unit *u,
|
||||
@@ -2417,6 +2431,10 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
|
||||
/* Make sure it's NUL-terminated. */
|
||||
buf[n] = 0;
|
||||
|
||||
/* possibly a barrier fd, let's see */
|
||||
if (manager_process_barrier_fd(buf, fds))
|
||||
return 0;
|
||||
|
||||
/* Increase the generation counter used for filtering out duplicate unit invocations. */
|
||||
m->notifygen++;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user