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