|
|
803fb7 |
From 92b12c7dc013c95bd0d35bae99ff6df023ce0e1f Mon Sep 17 00:00:00 2001
|
|
|
803fb7 |
From: Lennart Poettering <lennart@poettering.net>
|
|
|
803fb7 |
Date: Wed, 4 May 2016 20:43:23 +0200
|
|
|
803fb7 |
Subject: [PATCH] core: use an AF_UNIX/SOCK_DGRAM socket for cgroup agent
|
|
|
803fb7 |
notification
|
|
|
803fb7 |
|
|
|
803fb7 |
dbus-daemon currently uses a backlog of 30 on its D-bus system bus socket. On
|
|
|
803fb7 |
overloaded systems this means that only 30 connections may be queued without
|
|
|
803fb7 |
dbus-daemon processing them before further connection attempts fail. Our
|
|
|
803fb7 |
cgroups-agent binary so far used D-Bus for its messaging, and hitting this
|
|
|
803fb7 |
limit hence may result in us losing cgroup empty messages.
|
|
|
803fb7 |
|
|
|
803fb7 |
This patch adds a seperate cgroup agent socket of type AF_UNIX/SOCK_DGRAM.
|
|
|
803fb7 |
Since sockets of these types need no connection set up, no listen() backlog
|
|
|
803fb7 |
applies. Our cgroup-agent binary will hence simply block as long as it can't
|
|
|
803fb7 |
enqueue its datagram message, so that we won't lose cgroup empty messages as
|
|
|
803fb7 |
likely anymore.
|
|
|
803fb7 |
|
|
|
803fb7 |
This also rearranges the ordering of the processing of SIGCHLD signals, service
|
|
|
803fb7 |
notification messages (sd_notify()...) and the two types of cgroup
|
|
|
803fb7 |
notifications (inotify for the unified hierarchy support, and agent for the
|
|
|
803fb7 |
classic hierarchy support). We now always process events for these in the
|
|
|
803fb7 |
following order:
|
|
|
803fb7 |
|
|
|
803fb7 |
1. service notification messages (SD_EVENT_PRIORITY_NORMAL-7)
|
|
|
803fb7 |
2. SIGCHLD signals (SD_EVENT_PRIORITY_NORMAL-6)
|
|
|
803fb7 |
3. cgroup inotify and cgroup agent (SD_EVENT_PRIORITY_NORMAL-5)
|
|
|
803fb7 |
|
|
|
803fb7 |
This is because when receiving SIGCHLD we invalidate PID information, which we
|
|
|
803fb7 |
need to process the service notification messages which are bound to PIDs.
|
|
|
803fb7 |
Hence the order between the first two items. And we want to process SIGCHLD
|
|
|
803fb7 |
metadata to detect whether a service is gone, before using cgroup
|
|
|
803fb7 |
notifications, to decide when a service is gone, since the former carries more
|
|
|
803fb7 |
useful metadata.
|
|
|
803fb7 |
|
|
|
803fb7 |
Related to this:
|
|
|
803fb7 |
https://bugs.freedesktop.org/show_bug.cgi?id=95264
|
|
|
803fb7 |
https://github.com/systemd/systemd/issues/1961
|
|
|
803fb7 |
|
|
|
803fb7 |
Cherry-picked from: d8fdc62037b5b0a9fd603ad5efd6b49f956f86b5
|
|
|
803fb7 |
Resolves: #1305608
|
|
|
803fb7 |
---
|
|
|
803fb7 |
src/cgroups-agent/cgroups-agent.c | 48 ++++++------
|
|
|
803fb7 |
src/core/cgroup.c | 2 +
|
|
|
803fb7 |
src/core/dbus.c | 56 +++++++-------
|
|
|
803fb7 |
src/core/dbus.h | 2 +
|
|
|
803fb7 |
src/core/manager.c | 149 ++++++++++++++++++++++++++++++++++++--
|
|
|
803fb7 |
src/core/manager.h | 3 +
|
|
|
803fb7 |
6 files changed, 198 insertions(+), 62 deletions(-)
|
|
|
803fb7 |
|
|
|
803fb7 |
diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c
|
|
|
803fb7 |
index 529e84303..2fe65830e 100644
|
|
|
803fb7 |
--- a/src/cgroups-agent/cgroups-agent.c
|
|
|
803fb7 |
+++ b/src/cgroups-agent/cgroups-agent.c
|
|
|
803fb7 |
@@ -1,5 +1,3 @@
|
|
|
803fb7 |
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
|
|
803fb7 |
-
|
|
|
803fb7 |
/***
|
|
|
803fb7 |
This file is part of systemd.
|
|
|
803fb7 |
|
|
|
803fb7 |
@@ -20,14 +18,21 @@
|
|
|
803fb7 |
***/
|
|
|
803fb7 |
|
|
|
803fb7 |
#include <stdlib.h>
|
|
|
803fb7 |
+#include <sys/socket.h>
|
|
|
803fb7 |
|
|
|
803fb7 |
-#include "sd-bus.h"
|
|
|
803fb7 |
#include "log.h"
|
|
|
803fb7 |
-#include "bus-util.h"
|
|
|
803fb7 |
+#include "socket-util.h"
|
|
|
803fb7 |
|
|
|
803fb7 |
int main(int argc, char *argv[]) {
|
|
|
803fb7 |
- _cleanup_bus_close_unref_ sd_bus *bus = NULL;
|
|
|
803fb7 |
- int r;
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ static const union sockaddr_union sa = {
|
|
|
803fb7 |
+ .un.sun_family = AF_UNIX,
|
|
|
803fb7 |
+ .un.sun_path = "/run/systemd/cgroups-agent",
|
|
|
803fb7 |
+ };
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ _cleanup_close_ int fd = -1;
|
|
|
803fb7 |
+ ssize_t n;
|
|
|
803fb7 |
+ size_t l;
|
|
|
803fb7 |
|
|
|
803fb7 |
if (argc != 2) {
|
|
|
803fb7 |
log_error("Incorrect number of arguments.");
|
|
|
803fb7 |
@@ -38,27 +43,22 @@ int main(int argc, char *argv[]) {
|
|
|
803fb7 |
log_parse_environment();
|
|
|
803fb7 |
log_open();
|
|
|
803fb7 |
|
|
|
803fb7 |
- /* We send this event to the private D-Bus socket and then the
|
|
|
803fb7 |
- * system instance will forward this to the system bus. We do
|
|
|
803fb7 |
- * this to avoid an activation loop when we start dbus when we
|
|
|
803fb7 |
- * are called when the dbus service is shut down. */
|
|
|
803fb7 |
-
|
|
|
803fb7 |
- r = bus_open_system_systemd(&bus;;
|
|
|
803fb7 |
- if (r < 0) {
|
|
|
803fb7 |
- /* If we couldn't connect we assume this was triggered
|
|
|
803fb7 |
- * while systemd got restarted/transitioned from
|
|
|
803fb7 |
- * initrd to the system, so let's ignore this */
|
|
|
803fb7 |
- log_debug_errno(r, "Failed to get D-Bus connection: %m");
|
|
|
803fb7 |
+ fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
|
|
|
803fb7 |
+ if (fd < 0) {
|
|
|
803fb7 |
+ log_debug_errno(errno, "Failed to allocate socket: %m");
|
|
|
803fb7 |
+ return EXIT_FAILURE;
|
|
|
803fb7 |
+ }
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ l = strlen(argv[1]);
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ n = sendto(fd, argv[1], l, 0, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
|
|
|
803fb7 |
+ if (n < 0) {
|
|
|
803fb7 |
+ log_debug_errno(errno, "Failed to send cgroups agent message: %m");
|
|
|
803fb7 |
return EXIT_FAILURE;
|
|
|
803fb7 |
}
|
|
|
803fb7 |
|
|
|
803fb7 |
- r = sd_bus_emit_signal(bus,
|
|
|
803fb7 |
- "/org/freedesktop/systemd1/agent",
|
|
|
803fb7 |
- "org.freedesktop.systemd1.Agent",
|
|
|
803fb7 |
- "Released",
|
|
|
803fb7 |
- "s", argv[1]);
|
|
|
803fb7 |
- if (r < 0) {
|
|
|
803fb7 |
- log_debug_errno(r, "Failed to send signal message on private connection: %m");
|
|
|
803fb7 |
+ if ((size_t) n != l) {
|
|
|
803fb7 |
+ log_debug("Datagram size mismatch");
|
|
|
803fb7 |
return EXIT_FAILURE;
|
|
|
803fb7 |
}
|
|
|
803fb7 |
|
|
|
803fb7 |
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
|
|
|
803fb7 |
index 10fdcc998..b7f08fb42 100644
|
|
|
803fb7 |
--- a/src/core/cgroup.c
|
|
|
803fb7 |
+++ b/src/core/cgroup.c
|
|
|
803fb7 |
@@ -1028,6 +1028,8 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
|
|
|
803fb7 |
assert(m);
|
|
|
803fb7 |
assert(cgroup);
|
|
|
803fb7 |
|
|
|
803fb7 |
+ log_debug("Got cgroup empty notification for: %s", cgroup);
|
|
|
803fb7 |
+
|
|
|
803fb7 |
u = manager_get_unit_by_cgroup(m, cgroup);
|
|
|
803fb7 |
if (u) {
|
|
|
803fb7 |
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
|
|
|
803fb7 |
diff --git a/src/core/dbus.c b/src/core/dbus.c
|
|
|
803fb7 |
index 85b517486..29524d49a 100644
|
|
|
803fb7 |
--- a/src/core/dbus.c
|
|
|
803fb7 |
+++ b/src/core/dbus.c
|
|
|
803fb7 |
@@ -72,12 +72,37 @@ int bus_send_queued_message(Manager *m) {
|
|
|
803fb7 |
return 0;
|
|
|
803fb7 |
}
|
|
|
803fb7 |
|
|
|
803fb7 |
+int bus_forward_agent_released(Manager *m, const char *path) {
|
|
|
803fb7 |
+ int r;
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ assert(m);
|
|
|
803fb7 |
+ assert(path);
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ if (!m->running_as == SYSTEMD_SYSTEM)
|
|
|
803fb7 |
+ return 0;
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ if (!m->system_bus)
|
|
|
803fb7 |
+ return 0;
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ /* If we are running a system instance we forward the agent message on the system bus, so that the user
|
|
|
803fb7 |
+ * instances get notified about this, too */
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ r = sd_bus_emit_signal(m->system_bus,
|
|
|
803fb7 |
+ "/org/freedesktop/systemd1/agent",
|
|
|
803fb7 |
+ "org.freedesktop.systemd1.Agent",
|
|
|
803fb7 |
+ "Released",
|
|
|
803fb7 |
+ "s", path);
|
|
|
803fb7 |
+ if (r < 0)
|
|
|
803fb7 |
+ return log_warning_errno(r, "Failed to propagate agent release message: %m");
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ return 1;
|
|
|
803fb7 |
+}
|
|
|
803fb7 |
+
|
|
|
803fb7 |
static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
|
|
803fb7 |
Manager *m = userdata;
|
|
|
803fb7 |
const char *cgroup;
|
|
|
803fb7 |
int r;
|
|
|
803fb7 |
|
|
|
803fb7 |
- assert(bus);
|
|
|
803fb7 |
assert(message);
|
|
|
803fb7 |
assert(m);
|
|
|
803fb7 |
|
|
|
803fb7 |
@@ -88,16 +113,6 @@ static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *use
|
|
|
803fb7 |
}
|
|
|
803fb7 |
|
|
|
803fb7 |
manager_notify_cgroup_empty(m, cgroup);
|
|
|
803fb7 |
-
|
|
|
803fb7 |
- if (m->running_as == SYSTEMD_SYSTEM && m->system_bus) {
|
|
|
803fb7 |
- /* If we are running as system manager, forward the
|
|
|
803fb7 |
- * message to the system bus */
|
|
|
803fb7 |
-
|
|
|
803fb7 |
- r = sd_bus_send(m->system_bus, message, NULL);
|
|
|
803fb7 |
- if (r < 0)
|
|
|
803fb7 |
- log_warning_errno(r, "Failed to forward Released message: %m");
|
|
|
803fb7 |
- }
|
|
|
803fb7 |
-
|
|
|
803fb7 |
return 0;
|
|
|
803fb7 |
}
|
|
|
803fb7 |
|
|
|
803fb7 |
@@ -679,25 +694,6 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
|
|
|
803fb7 |
return 0;
|
|
|
803fb7 |
}
|
|
|
803fb7 |
|
|
|
803fb7 |
- if (m->running_as == SYSTEMD_SYSTEM) {
|
|
|
803fb7 |
- /* When we run as system instance we get the Released
|
|
|
803fb7 |
- * signal via a direct connection */
|
|
|
803fb7 |
-
|
|
|
803fb7 |
- r = sd_bus_add_match(
|
|
|
803fb7 |
- bus,
|
|
|
803fb7 |
- NULL,
|
|
|
803fb7 |
- "type='signal',"
|
|
|
803fb7 |
- "interface='org.freedesktop.systemd1.Agent',"
|
|
|
803fb7 |
- "member='Released',"
|
|
|
803fb7 |
- "path='/org/freedesktop/systemd1/agent'",
|
|
|
803fb7 |
- signal_agent_released, m);
|
|
|
803fb7 |
-
|
|
|
803fb7 |
- if (r < 0) {
|
|
|
803fb7 |
- log_warning_errno(r, "Failed to register Released match on new connection bus: %m");
|
|
|
803fb7 |
- return 0;
|
|
|
803fb7 |
- }
|
|
|
803fb7 |
- }
|
|
|
803fb7 |
-
|
|
|
803fb7 |
r = bus_setup_disconnected_match(m, bus);
|
|
|
803fb7 |
if (r < 0)
|
|
|
803fb7 |
return 0;
|
|
|
803fb7 |
diff --git a/src/core/dbus.h b/src/core/dbus.h
|
|
|
803fb7 |
index d04f5326c..c27d136e3 100644
|
|
|
803fb7 |
--- a/src/core/dbus.h
|
|
|
803fb7 |
+++ b/src/core/dbus.h
|
|
|
803fb7 |
@@ -40,3 +40,5 @@ int bus_verify_manage_unit_async(Manager *m, sd_bus_message *call, sd_bus_error
|
|
|
803fb7 |
int bus_verify_manage_unit_async_for_kill(Manager *m, sd_bus_message *call, sd_bus_error *error);
|
|
|
803fb7 |
int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
|
|
|
803fb7 |
int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+int bus_forward_agent_released(Manager *m, const char *path);
|
|
|
803fb7 |
diff --git a/src/core/manager.c b/src/core/manager.c
|
|
|
803fb7 |
index ee456fb79..370c8cbbe 100644
|
|
|
803fb7 |
--- a/src/core/manager.c
|
|
|
803fb7 |
+++ b/src/core/manager.c
|
|
|
803fb7 |
@@ -83,8 +83,10 @@
|
|
|
803fb7 |
#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
|
|
|
803fb7 |
#define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3)
|
|
|
803fb7 |
#define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3
|
|
|
803fb7 |
+#define CGROUPS_AGENT_RCVBUF_SIZE (8*1024*1024)
|
|
|
803fb7 |
|
|
|
803fb7 |
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
|
|
|
803fb7 |
+static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
|
|
|
803fb7 |
static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
|
|
|
803fb7 |
static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
|
|
|
803fb7 |
static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
|
|
|
803fb7 |
@@ -456,11 +458,11 @@ static int manager_setup_signals(Manager *m) {
|
|
|
803fb7 |
if (r < 0)
|
|
|
803fb7 |
return r;
|
|
|
803fb7 |
|
|
|
803fb7 |
- /* Process signals a bit earlier than the rest of things, but
|
|
|
803fb7 |
- * later than notify_fd processing, so that the notify
|
|
|
803fb7 |
- * processing can still figure out to which process/service a
|
|
|
803fb7 |
- * message belongs, before we reap the process. */
|
|
|
803fb7 |
- r = sd_event_source_set_priority(m->signal_event_source, -5);
|
|
|
803fb7 |
+ /* Process signals a bit earlier than the rest of things, but later than notify_fd processing, so that the
|
|
|
803fb7 |
+ * notify processing can still figure out to which process/service a message belongs, before we reap the
|
|
|
803fb7 |
+ * process. Also, process this before handling cgroup notifications, so that we always collect child exit
|
|
|
803fb7 |
+ * status information before detecting that there's no process in a cgroup. */
|
|
|
803fb7 |
+ r = sd_event_source_set_priority(m->signal_event_source, -6);
|
|
|
803fb7 |
if (r < 0)
|
|
|
803fb7 |
return r;
|
|
|
803fb7 |
|
|
|
803fb7 |
@@ -541,7 +543,7 @@ int manager_new(SystemdRunningAs running_as, bool test_run, Manager **_m) {
|
|
|
803fb7 |
|
|
|
803fb7 |
m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
|
|
|
803fb7 |
|
|
|
803fb7 |
- m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd = m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->utab_inotify_fd = -1;
|
|
|
803fb7 |
+ m->pin_cgroupfs_fd = m->notify_fd = m->cgroups_agent_fd = m->signal_fd = m->time_change_fd = m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->utab_inotify_fd = -1;
|
|
|
803fb7 |
m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
|
|
|
803fb7 |
|
|
|
803fb7 |
m->ask_password_inotify_fd = -1;
|
|
|
803fb7 |
@@ -689,8 +691,8 @@ static int manager_setup_notify(Manager *m) {
|
|
|
803fb7 |
if (r < 0)
|
|
|
803fb7 |
return log_error_errno(r, "Failed to allocate notify event source: %m");
|
|
|
803fb7 |
|
|
|
803fb7 |
- /* Process signals a bit earlier than SIGCHLD, so that we can
|
|
|
803fb7 |
- * still identify to which service an exit message belongs */
|
|
|
803fb7 |
+ /* Process notification messages a bit earlier than SIGCHLD, so that we can still identify to which
|
|
|
803fb7 |
+ * service an exit message belongs. */
|
|
|
803fb7 |
r = sd_event_source_set_priority(m->notify_event_source, -7);
|
|
|
803fb7 |
if (r < 0)
|
|
|
803fb7 |
return log_error_errno(r, "Failed to set priority of notify event source: %m");
|
|
|
803fb7 |
@@ -699,6 +701,77 @@ static int manager_setup_notify(Manager *m) {
|
|
|
803fb7 |
return 0;
|
|
|
803fb7 |
}
|
|
|
803fb7 |
|
|
|
803fb7 |
+static int manager_setup_cgroups_agent(Manager *m) {
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ static const union sockaddr_union sa = {
|
|
|
803fb7 |
+ .un.sun_family = AF_UNIX,
|
|
|
803fb7 |
+ .un.sun_path = "/run/systemd/cgroups-agent",
|
|
|
803fb7 |
+ };
|
|
|
803fb7 |
+ int r;
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ /* This creates a listening socket we receive cgroups agent messages on. We do not use D-Bus for delivering
|
|
|
803fb7 |
+ * these messages from the cgroups agent binary to PID 1, as the cgroups agent binary is very short-living, and
|
|
|
803fb7 |
+ * each instance of it needs a new D-Bus connection. Since D-Bus connections are SOCK_STREAM/AF_UNIX, on
|
|
|
803fb7 |
+ * overloaded systems the backlog of the D-Bus socket becomes relevant, as not more than the configured number
|
|
|
803fb7 |
+ * of D-Bus connections may be queued until the kernel will start dropping further incoming connections,
|
|
|
803fb7 |
+ * possibly resulting in lost cgroups agent messages. To avoid this, we'll use a private SOCK_DGRAM/AF_UNIX
|
|
|
803fb7 |
+ * socket, where no backlog is relevant as communication may take place without an actual connect() cycle, and
|
|
|
803fb7 |
+ * we thus won't lose messages.
|
|
|
803fb7 |
+ *
|
|
|
803fb7 |
+ * Note that PID 1 will forward the agent message to system bus, so that the user systemd instance may listen
|
|
|
803fb7 |
+ * to it. The system instance hence listens on this special socket, but the user instances listen on the system
|
|
|
803fb7 |
+ * bus for these messages. */
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ if (m->test_run)
|
|
|
803fb7 |
+ return 0;
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ if (!m->running_as == SYSTEMD_SYSTEM)
|
|
|
803fb7 |
+ return 0;
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ if (m->cgroups_agent_fd < 0) {
|
|
|
803fb7 |
+ _cleanup_close_ int fd = -1;
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ /* First free all secondary fields */
|
|
|
803fb7 |
+ m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source);
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
|
|
803fb7 |
+ if (fd < 0)
|
|
|
803fb7 |
+ return log_error_errno(errno, "Failed to allocate cgroups agent socket: %m");
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ fd_inc_rcvbuf(fd, CGROUPS_AGENT_RCVBUF_SIZE);
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ (void) unlink(sa.un.sun_path);
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ /* Only allow root to connect to this socket */
|
|
|
803fb7 |
+ RUN_WITH_UMASK(0077)
|
|
|
803fb7 |
+ r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
|
|
|
803fb7 |
+ if (r < 0)
|
|
|
803fb7 |
+ return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ m->cgroups_agent_fd = fd;
|
|
|
803fb7 |
+ fd = -1;
|
|
|
803fb7 |
+ }
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ if (!m->cgroups_agent_event_source) {
|
|
|
803fb7 |
+ r = sd_event_add_io(m->event, &m->cgroups_agent_event_source, m->cgroups_agent_fd, EPOLLIN, manager_dispatch_cgroups_agent_fd, m);
|
|
|
803fb7 |
+ if (r < 0)
|
|
|
803fb7 |
+ return log_error_errno(r, "Failed to allocate cgroups agent event source: %m");
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ /* Process cgroups notifications early, but after having processed service notification messages or
|
|
|
803fb7 |
+ * SIGCHLD signals, so that a cgroup running empty is always just the last safety net of notification,
|
|
|
803fb7 |
+ * and we collected the metadata the notification and SIGCHLD stuff offers first. Also see handling of
|
|
|
803fb7 |
+ * cgroup inotify for the unified cgroup stuff. */
|
|
|
803fb7 |
+ r = sd_event_source_set_priority(m->cgroups_agent_event_source, SD_EVENT_PRIORITY_NORMAL-5);
|
|
|
803fb7 |
+ if (r < 0)
|
|
|
803fb7 |
+ return log_error_errno(r, "Failed to set priority of cgroups agent event source: %m");
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ (void) sd_event_source_set_description(m->cgroups_agent_event_source, "manager-cgroups-agent");
|
|
|
803fb7 |
+ }
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ return 0;
|
|
|
803fb7 |
+}
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+
|
|
|
803fb7 |
static int manager_setup_kdbus(Manager *m) {
|
|
|
803fb7 |
#ifdef ENABLE_KDBUS
|
|
|
803fb7 |
_cleanup_free_ char *p = NULL;
|
|
|
803fb7 |
@@ -912,6 +985,7 @@ Manager* manager_free(Manager *m) {
|
|
|
803fb7 |
|
|
|
803fb7 |
sd_event_source_unref(m->signal_event_source);
|
|
|
803fb7 |
sd_event_source_unref(m->notify_event_source);
|
|
|
803fb7 |
+ sd_event_source_unref(m->cgroups_agent_event_source);
|
|
|
803fb7 |
sd_event_source_unref(m->time_change_event_source);
|
|
|
803fb7 |
sd_event_source_unref(m->jobs_in_progress_event_source);
|
|
|
803fb7 |
sd_event_source_unref(m->idle_pipe_event_source);
|
|
|
803fb7 |
@@ -919,6 +993,7 @@ Manager* manager_free(Manager *m) {
|
|
|
803fb7 |
|
|
|
803fb7 |
safe_close(m->signal_fd);
|
|
|
803fb7 |
safe_close(m->notify_fd);
|
|
|
803fb7 |
+ safe_close(m->cgroups_agent_fd);
|
|
|
803fb7 |
safe_close(m->time_change_fd);
|
|
|
803fb7 |
safe_close(m->kdbus_fd);
|
|
|
803fb7 |
|
|
|
803fb7 |
@@ -1167,6 +1242,10 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
|
|
|
803fb7 |
if (q < 0 && r == 0)
|
|
|
803fb7 |
r = q;
|
|
|
803fb7 |
|
|
|
803fb7 |
+ q = manager_setup_cgroups_agent(m);
|
|
|
803fb7 |
+ if (q < 0 && r == 0)
|
|
|
803fb7 |
+ r = q;
|
|
|
803fb7 |
+
|
|
|
803fb7 |
/* We might have deserialized the kdbus control fd, but if we
|
|
|
803fb7 |
* didn't, then let's create the bus now. */
|
|
|
803fb7 |
manager_setup_kdbus(m);
|
|
|
803fb7 |
@@ -1492,6 +1571,35 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) {
|
|
|
803fb7 |
return n;
|
|
|
803fb7 |
}
|
|
|
803fb7 |
|
|
|
803fb7 |
+static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
|
|
|
803fb7 |
+ Manager *m = userdata;
|
|
|
803fb7 |
+ char buf[PATH_MAX+1];
|
|
|
803fb7 |
+ ssize_t n;
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ n = recv(fd, buf, sizeof(buf), 0);
|
|
|
803fb7 |
+ if (n < 0)
|
|
|
803fb7 |
+ return log_error_errno(errno, "Failed to read cgroups agent message: %m");
|
|
|
803fb7 |
+ if (n == 0) {
|
|
|
803fb7 |
+ log_error("Got zero-length cgroups agent message, ignoring.");
|
|
|
803fb7 |
+ return 0;
|
|
|
803fb7 |
+ }
|
|
|
803fb7 |
+ if ((size_t) n >= sizeof(buf)) {
|
|
|
803fb7 |
+ log_error("Got overly long cgroups agent message, ignoring.");
|
|
|
803fb7 |
+ return 0;
|
|
|
803fb7 |
+ }
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ if (memchr(buf, 0, n)) {
|
|
|
803fb7 |
+ log_error("Got cgroups agent message with embedded NUL byte, ignoring.");
|
|
|
803fb7 |
+ return 0;
|
|
|
803fb7 |
+ }
|
|
|
803fb7 |
+ buf[n] = 0;
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ manager_notify_cgroup_empty(m, buf);
|
|
|
803fb7 |
+ bus_forward_agent_released(m, buf);
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ return 0;
|
|
|
803fb7 |
+}
|
|
|
803fb7 |
+
|
|
|
803fb7 |
static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *buf, size_t n, FDSet *fds) {
|
|
|
803fb7 |
_cleanup_strv_free_ char **tags = NULL;
|
|
|
803fb7 |
|
|
|
803fb7 |
@@ -2304,6 +2412,16 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
|
|
|
803fb7 |
fprintf(f, "notify-socket=%s\n", m->notify_socket);
|
|
|
803fb7 |
}
|
|
|
803fb7 |
|
|
|
803fb7 |
+ if (m->cgroups_agent_fd >= 0) {
|
|
|
803fb7 |
+ int copy;
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ copy = fdset_put_dup(fds, m->cgroups_agent_fd);
|
|
|
803fb7 |
+ if (copy < 0)
|
|
|
803fb7 |
+ return copy;
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ fprintf(f, "cgroups-agent-fd=%i\n", copy);
|
|
|
803fb7 |
+ }
|
|
|
803fb7 |
+
|
|
|
803fb7 |
if (m->kdbus_fd >= 0) {
|
|
|
803fb7 |
int copy;
|
|
|
803fb7 |
|
|
|
803fb7 |
@@ -2473,6 +2591,17 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
|
|
|
803fb7 |
free(m->notify_socket);
|
|
|
803fb7 |
m->notify_socket = n;
|
|
|
803fb7 |
|
|
|
803fb7 |
+ } else if (startswith(l, "cgroups-agent-fd=")) {
|
|
|
803fb7 |
+ int fd;
|
|
|
803fb7 |
+
|
|
|
803fb7 |
+ if (safe_atoi(l + 17, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
|
|
|
803fb7 |
+ log_debug("Failed to parse cgroups agent fd: %s", l + 10);
|
|
|
803fb7 |
+ else {
|
|
|
803fb7 |
+ m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source);
|
|
|
803fb7 |
+ safe_close(m->cgroups_agent_fd);
|
|
|
803fb7 |
+ m->cgroups_agent_fd = fdset_remove(fds, fd);
|
|
|
803fb7 |
+ }
|
|
|
803fb7 |
+
|
|
|
803fb7 |
} else if (startswith(l, "kdbus-fd=")) {
|
|
|
803fb7 |
int fd;
|
|
|
803fb7 |
|
|
|
803fb7 |
@@ -2599,6 +2728,10 @@ int manager_reload(Manager *m) {
|
|
|
803fb7 |
if (q < 0 && r >= 0)
|
|
|
803fb7 |
r = q;
|
|
|
803fb7 |
|
|
|
803fb7 |
+ q = manager_setup_cgroups_agent(m);
|
|
|
803fb7 |
+ if (q < 0 && r >= 0)
|
|
|
803fb7 |
+ r = q;
|
|
|
803fb7 |
+
|
|
|
803fb7 |
/* Third, fire things up! */
|
|
|
803fb7 |
q = manager_coldplug(m);
|
|
|
803fb7 |
if (q < 0 && r >= 0)
|
|
|
803fb7 |
diff --git a/src/core/manager.h b/src/core/manager.h
|
|
|
803fb7 |
index d3971f168..3e855db46 100644
|
|
|
803fb7 |
--- a/src/core/manager.h
|
|
|
803fb7 |
+++ b/src/core/manager.h
|
|
|
803fb7 |
@@ -137,6 +137,9 @@ struct Manager {
|
|
|
803fb7 |
int notify_fd;
|
|
|
803fb7 |
sd_event_source *notify_event_source;
|
|
|
803fb7 |
|
|
|
803fb7 |
+ int cgroups_agent_fd;
|
|
|
803fb7 |
+ sd_event_source *cgroups_agent_event_source;
|
|
|
803fb7 |
+
|
|
|
803fb7 |
int signal_fd;
|
|
|
803fb7 |
sd_event_source *signal_event_source;
|
|
|
803fb7 |
|