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:
Kumar Kartikeya Dwivedi
2020-05-01 03:22:47 +05:30
parent cad6727906
commit 4f07ddfa9b
6 changed files with 130 additions and 1 deletions
+18
View File
@@ -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++;