chiark / gitweb /
core: use an AF_UNIX/SOCK_DGRAM socket for cgroup agent notification
[elogind.git] / src / core / cgroup.c
index 792f0d9119936402f2a178980c4504b84f5601e2..6a6f066128c57b1c0b46b9bdcef5e48b8a2a46f4 100644 (file)
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
 /***
   This file is part of systemd.
 
 #include <fcntl.h>
 #include <fnmatch.h>
 
+#include "alloc-util.h"
 #include "cgroup-util.h"
+#include "cgroup.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
 //#include "special.h"
-
-#include "cgroup.h"
+#include "string-table.h"
+#include "string-util.h"
 
 #define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
 
-// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
 void cgroup_context_init(CGroupContext *c) {
         assert(c);
 
@@ -49,8 +52,6 @@ void cgroup_context_init(CGroupContext *c) {
         c->startup_blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID;
 
         c->tasks_max = (uint64_t) -1;
-
-        c->netclass_type = CGROUP_NETCLASS_TYPE_NONE;
 }
 
 void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a) {
@@ -295,7 +296,7 @@ fail:
         return -errno;
 }
 
-void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, uint32_t netclass, ManagerState state) {
+void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, ManagerState state) {
         bool is_root;
         int r;
 
@@ -493,17 +494,6 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
                         log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
                                        "Failed to set pids.max on %s: %m", path);
         }
-
-        if (mask & CGROUP_MASK_NET_CLS) {
-                char buf[DECIMAL_STR_MAX(uint32_t)];
-
-                sprintf(buf, "%" PRIu32, netclass);
-
-                r = cg_set_attribute("net_cls", path, "net_cls.classid", buf);
-                if (r < 0)
-                        log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
-                                       "Failed to set net_cls.classid on %s: %m", path);
-        }
 }
 
 CGroupMask cgroup_context_get_mask(CGroupContext *c) {
@@ -536,9 +526,6 @@ CGroupMask cgroup_context_get_mask(CGroupContext *c) {
             c->tasks_max != (uint64_t) -1)
                 mask |= CGROUP_MASK_PIDS;
 
-        if (c->netclass_type != CGROUP_NETCLASS_TYPE_NONE)
-                mask |= CGROUP_MASK_NET_CLS;
-
         return mask;
 }
 
@@ -779,7 +766,7 @@ int unit_set_cgroup_path(Unit *u, const char *path) {
 }
 
 int unit_watch_cgroup(Unit *u) {
-        _cleanup_free_ char *populated = NULL;
+        _cleanup_free_ char *events = NULL;
         int r;
 
         assert(u);
@@ -805,11 +792,11 @@ int unit_watch_cgroup(Unit *u) {
         if (r < 0)
                 return log_oom();
 
-        r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.populated", &populated);
+        r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.events", &events);
         if (r < 0)
                 return log_oom();
 
-        u->cgroup_inotify_wd = inotify_add_watch(u->manager->cgroup_inotify_fd, populated, IN_MODIFY);
+        u->cgroup_inotify_wd = inotify_add_watch(u->manager->cgroup_inotify_fd, events, IN_MODIFY);
         if (u->cgroup_inotify_wd < 0) {
 
                 if (errno == ENOENT) /* If the directory is already
@@ -871,6 +858,7 @@ static int unit_create_cgroup(
         /* Keep track that this is now realized */
         u->cgroup_realized = true;
         u->cgroup_realized_mask = target_mask;
+        u->cgroup_enabled_mask = enable_mask;
 
         if (u->type != UNIT_SLICE && !c->delegate) {
 
@@ -900,107 +888,10 @@ int unit_attach_pids_to_cgroup(Unit *u) {
         return 0;
 }
 
-static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask) {
+static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask, CGroupMask enable_mask) {
         assert(u);
 
-        return u->cgroup_realized && u->cgroup_realized_mask == target_mask;
-}
-
-static int unit_find_free_netclass_cgroup(Unit *u, uint32_t *ret) {
-
-        uint32_t start, i;
-        Manager *m;
-
-        assert(u);
-
-        m = u->manager;
-
-        i = start = m->cgroup_netclass_registry_last;
-
-        do {
-                i++;
-
-                if (!hashmap_get(m->cgroup_netclass_registry, UINT_TO_PTR(i))) {
-                        m->cgroup_netclass_registry_last = i;
-                        *ret = i;
-                        return 0;
-                }
-
-                if (i == UINT32_MAX)
-                        i = CGROUP_NETCLASS_FIXED_MAX;
-
-        } while (i != start);
-
-        return -ENOBUFS;
-}
-
-int unit_add_to_netclass_cgroup(Unit *u) {
-
-        CGroupContext *cc;
-        Unit *first;
-        void *key;
-        int r;
-
-        assert(u);
-
-        cc = unit_get_cgroup_context(u);
-        if (!cc)
-                return 0;
-
-        switch (cc->netclass_type) {
-        case CGROUP_NETCLASS_TYPE_NONE:
-                return 0;
-
-        case CGROUP_NETCLASS_TYPE_FIXED:
-                u->cgroup_netclass_id = cc->netclass_id;
-                break;
-
-        case CGROUP_NETCLASS_TYPE_AUTO:
-                /* Allocate a new ID in case it was requested and not done yet */
-                if (u->cgroup_netclass_id == 0) {
-                        r = unit_find_free_netclass_cgroup(u, &u->cgroup_netclass_id);
-                        if (r < 0)
-                                return r;
-
-                        log_debug("Dynamically assigned netclass cgroup id %" PRIu32 " to %s", u->cgroup_netclass_id, u->id);
-                }
-
-                break;
-        }
-
-        r = hashmap_ensure_allocated(&u->manager->cgroup_netclass_registry, &trivial_hash_ops);
-        if (r < 0)
-                return r;
-
-        key = UINT32_TO_PTR(u->cgroup_netclass_id);
-        first = hashmap_get(u->manager->cgroup_netclass_registry, key);
-
-        if (first) {
-                LIST_PREPEND(cgroup_netclass, first, u);
-                return hashmap_replace(u->manager->cgroup_netclass_registry, key, u);
-        }
-
-        return hashmap_put(u->manager->cgroup_netclass_registry, key, u);
-}
-
-int unit_remove_from_netclass_cgroup(Unit *u) {
-
-        Unit *head;
-        void *key;
-
-        assert(u);
-
-        key = UINT32_TO_PTR(u->cgroup_netclass_id);
-
-        LIST_FIND_HEAD(cgroup_netclass, u, head);
-        LIST_REMOVE(cgroup_netclass, head, u);
-
-        if (head)
-                return hashmap_replace(u->manager->cgroup_netclass_registry, key, head);
-
-        hashmap_remove(u->manager->cgroup_netclass_registry, key);
-
-        return 0;
+        return u->cgroup_realized && u->cgroup_realized_mask == target_mask && u->cgroup_enabled_mask == enable_mask;
 }
 
 /* Check if necessary controllers and attributes for a unit are in place.
@@ -1021,7 +912,9 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
         }
 
         target_mask = unit_get_target_mask(u);
-        if (unit_has_mask_realized(u, target_mask))
+        enable_mask = unit_get_enable_mask(u);
+
+        if (unit_has_mask_realized(u, target_mask, enable_mask))
                 return 0;
 
         /* First, realize parents */
@@ -1032,13 +925,12 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
         }
 
         /* And then do the real work */
-        enable_mask = unit_get_enable_mask(u);
         r = unit_create_cgroup(u, target_mask, enable_mask);
         if (r < 0)
                 return r;
 
         /* Finally, apply the necessary attributes. */
-        cgroup_context_apply(unit_get_cgroup_context(u), target_mask, u->cgroup_path, u->cgroup_netclass_id, state);
+        cgroup_context_apply(unit_get_cgroup_context(u), target_mask, u->cgroup_path, state);
 
         return 0;
 }
@@ -1101,7 +993,7 @@ static void unit_queue_siblings(Unit *u) {
                         /* If the unit doesn't need any new controllers
                          * and has current ones realized, it doesn't need
                          * any changes. */
-                        if (unit_has_mask_realized(m, unit_get_target_mask(m)))
+                        if (unit_has_mask_realized(m, unit_get_target_mask(m), unit_get_enable_mask(m)))
                                 continue;
 
                         unit_add_to_cgroup_queue(m);
@@ -1180,6 +1072,7 @@ void unit_prune_cgroup(Unit *u) {
 
         u->cgroup_realized = false;
         u->cgroup_realized_mask = 0;
+        u->cgroup_enabled_mask = 0;
 }
 
 int unit_search_main_pid(Unit *u, pid_t *ret) {
@@ -1205,7 +1098,7 @@ int unit_search_main_pid(Unit *u, pid_t *ret) {
                         continue;
 
                 /* Ignore processes that aren't our kids */
-                if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
+                if (get_process_ppid(npid, &ppid) >= 0 && ppid != mypid)
                         continue;
 
                 if (pid != 0)
@@ -1370,8 +1263,7 @@ int manager_setup_cgroup(Manager *m) {
         if (r < 0)
                 return log_error_errno(r, "Cannot determine cgroup we are running in: %m");
 
-/// elogind does not support systemd scopes and slices
-#if 0
+#if 0 /// elogind does not support systemd scopes and slices
         /* Chop off the init scope, if we are already located in it */
         e = endswith(m->cgroup_root, "/" SPECIAL_INIT_SCOPE);
 
@@ -1418,8 +1310,7 @@ int manager_setup_cgroup(Manager *m) {
                         /* In the unified hierarchy we can can get
                          * cgroup empty notifications via inotify. */
 
-/// elogind does not support the unified hierarchy, yet.
-#if 0
+#if 0 /// elogind does not support the unified hierarchy, yet.
                         m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source);
                         safe_close(m->cgroup_inotify_fd);
 
@@ -1431,7 +1322,9 @@ int manager_setup_cgroup(Manager *m) {
                         if (r < 0)
                                 return log_error_errno(r, "Failed to watch control group inotify object: %m");
 
-                        r = sd_event_source_set_priority(m->cgroup_inotify_event_source, SD_EVENT_PRIORITY_IDLE - 5);
+                        /* Process cgroup empty notifications early, but after service notifications and SIGCHLD. Also
+                         * see handling of cgroup agent notifications, for the classic cgroup hierarchy support. */
+                        r = sd_event_source_set_priority(m->cgroup_inotify_event_source, SD_EVENT_PRIORITY_NORMAL-5);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to set priority of inotify event source: %m");
 
@@ -1457,8 +1350,7 @@ int manager_setup_cgroup(Manager *m) {
                                 log_debug("Release agent already installed.");
                 }
 
-/// elogind is not meant to run in systemd init scope
-#if 0
+#if 0 /// elogind is not meant to run in systemd init scope
                 /* 4. Make sure we are in the special "init.scope" unit in the root slice. */
                 scope_path = strjoina(m->cgroup_root, "/" SPECIAL_INIT_SCOPE);
                 r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, scope_path, 0);
@@ -1516,8 +1408,7 @@ void manager_shutdown_cgroup(Manager *m, bool delete) {
         if (delete && m->cgroup_root)
                 (void) cg_trim(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, false);
 
-/// elogind does not support the unified hierarchy, yet.
-#if 0
+#if 0 /// elogind does not support the unified hierarchy, yet.
         m->cgroup_inotify_wd_unit = hashmap_free(m->cgroup_inotify_wd_unit);
 
         m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source);
@@ -1529,8 +1420,7 @@ void manager_shutdown_cgroup(Manager *m, bool delete) {
         m->cgroup_root = mfree(m->cgroup_root);
 }
 
-/// UNNEEDED by elogind
-#if 0
+#if 0 /// UNNEEDED by elogind
 Unit* manager_get_unit_by_cgroup(Manager *m, const char *cgroup) {
         char *p;
         Unit *u;
@@ -1602,6 +1492,8 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
         assert(m);
         assert(cgroup);
 
+        log_debug("Got cgroup empty notification for: %s", cgroup);
+
         u = manager_get_unit_by_cgroup(m, cgroup);
         if (!u)
                 return 0;