1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include <sys/types.h>
27 #include <sys/mount.h>
31 #include "cgroup-util.h"
34 #include "path-util.h"
37 int cgroup_bonding_realize(CGroupBonding *b) {
42 assert(b->controller);
44 r = cg_create(b->controller, b->path, NULL);
46 log_warning("Failed to create cgroup %s:%s: %s", b->controller, b->path, strerror(-r));
55 int cgroup_bonding_realize_list(CGroupBonding *first) {
59 LIST_FOREACH(by_unit, b, first)
60 if ((r = cgroup_bonding_realize(b)) < 0 && b->essential)
66 void cgroup_bonding_free(CGroupBonding *b, bool trim) {
72 LIST_REMOVE(CGroupBonding, by_unit, b->unit->cgroup_bondings, b);
74 if (streq(b->controller, SYSTEMD_CGROUP_CONTROLLER)) {
75 assert_se(f = hashmap_get(b->unit->manager->cgroup_bondings, b->path));
76 LIST_REMOVE(CGroupBonding, by_path, f, b);
79 hashmap_replace(b->unit->manager->cgroup_bondings, b->path, f);
81 hashmap_remove(b->unit->manager->cgroup_bondings, b->path);
85 if (b->realized && b->ours && trim)
86 cg_trim(b->controller, b->path, false);
93 void cgroup_bonding_free_list(CGroupBonding *first, bool remove_or_trim) {
96 LIST_FOREACH_SAFE(by_unit, b, n, first)
97 cgroup_bonding_free(b, remove_or_trim);
100 void cgroup_bonding_trim(CGroupBonding *b, bool delete_root) {
103 if (b->realized && b->ours)
104 cg_trim(b->controller, b->path, delete_root);
107 void cgroup_bonding_trim_list(CGroupBonding *first, bool delete_root) {
110 LIST_FOREACH(by_unit, b, first)
111 cgroup_bonding_trim(b, delete_root);
114 int cgroup_bonding_install(CGroupBonding *b, pid_t pid, const char *cgroup_suffix) {
115 _cleanup_free_ char *p = NULL;
123 p = strjoin(b->path, "/", cgroup_suffix, NULL);
131 r = cg_create_and_attach(b->controller, path, pid);
139 int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid, const char *cgroup_suffix) {
143 LIST_FOREACH(by_unit, b, first) {
144 r = cgroup_bonding_install(b, pid, cgroup_suffix);
145 if (r < 0 && b->essential)
152 int cgroup_bonding_migrate(CGroupBonding *b, CGroupBonding *list) {
156 LIST_FOREACH(by_unit, q, list) {
165 r = cg_migrate_recursive(q->controller, q->path, b->controller, b->path, true, false);
166 if (r < 0 && ret == 0)
173 int cgroup_bonding_migrate_to(CGroupBonding *b, const char *target, bool rem) {
177 return cg_migrate_recursive(b->controller, b->path, b->controller, target, true, rem);
180 int cgroup_bonding_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid) {
186 return cg_set_group_access(b->controller, b->path, mode, uid, gid);
189 int cgroup_bonding_set_group_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid) {
193 LIST_FOREACH(by_unit, b, first) {
194 r = cgroup_bonding_set_group_access(b, mode, uid, gid);
202 int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky) {
208 return cg_set_task_access(b->controller, b->path, mode, uid, gid, sticky);
211 int cgroup_bonding_set_task_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid, int sticky) {
215 LIST_FOREACH(by_unit, b, first) {
216 r = cgroup_bonding_set_task_access(b, mode, uid, gid, sticky);
224 int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, bool rem, Set *s, const char *cgroup_suffix) {
232 /* Don't kill cgroups that aren't ours */
237 p = strjoin(b->path, "/", cgroup_suffix, NULL);
245 r = cg_kill_recursive(b->controller, path, sig, sigcont, true, rem, s);
251 int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, bool rem, Set *s, const char *cgroup_suffix) {
253 Set *allocated_set = NULL;
254 int ret = -EAGAIN, r;
260 if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
263 LIST_FOREACH(by_unit, b, first) {
264 r = cgroup_bonding_kill(b, sig, sigcont, rem, s, cgroup_suffix);
266 if (r == -EAGAIN || r == -ESRCH)
273 if (ret < 0 || r > 0)
279 set_free(allocated_set);
284 /* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we
286 int cgroup_bonding_is_empty(CGroupBonding *b) {
291 if ((r = cg_is_empty_recursive(b->controller, b->path, true)) < 0)
294 /* If it is empty it is empty */
298 /* It's not only us using this cgroup, so we just don't know */
299 return b->ours ? 0 : -EAGAIN;
302 int cgroup_bonding_is_empty_list(CGroupBonding *first) {
305 LIST_FOREACH(by_unit, b, first) {
308 r = cgroup_bonding_is_empty(b);
310 /* If this returned -EAGAIN, then we don't know if the
311 * group is empty, so let's see if another group can
323 int manager_setup_cgroup(Manager *m) {
324 _cleanup_free_ char *path = NULL;
330 /* 0. Be nice to Ingo Molnar #628004 */
331 if (path_is_mount_point("/sys/fs/cgroup/systemd", false) <= 0) {
332 log_warning("No control group support available, not creating root group.");
336 /* 1. Determine hierarchy */
337 free(m->cgroup_root);
338 m->cgroup_root = NULL;
340 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &m->cgroup_root);
342 log_error("Cannot determine cgroup we are running in: %s", strerror(-r));
346 /* Already in /system.slice? If so, let's cut this off again */
347 if (m->running_as == SYSTEMD_SYSTEM) {
348 e = endswith(m->cgroup_root, "/" SPECIAL_SYSTEM_SLICE);
353 /* And make sure to store away the root value without trailing
354 * slash, even for the root dir, so that we can easily prepend
356 if (streq(m->cgroup_root, "/"))
357 m->cgroup_root[0] = 0;
360 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, NULL, &path);
362 log_error("Cannot find cgroup mount point: %s", strerror(-r));
366 log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
368 /* 3. Install agent */
369 if (m->running_as == SYSTEMD_SYSTEM) {
370 r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH);
372 log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
374 log_debug("Installed release agent.");
376 log_debug("Release agent already installed.");
379 /* 4. Realize the system slice and put us in there */
380 a = strappenda(m->cgroup_root, "/" SPECIAL_SYSTEM_SLICE);
381 r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, a, 0);
383 log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
387 /* 5. And pin it, so that it cannot be unmounted */
388 if (m->pin_cgroupfs_fd >= 0)
389 close_nointr_nofail(m->pin_cgroupfs_fd);
391 m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
393 log_error("Failed to open pin file: %m");
397 /* 6. Remove non-existing controllers from the default controllers list */
398 cg_shorten_controllers(m->default_controllers);
403 void manager_shutdown_cgroup(Manager *m, bool delete) {
406 /* We can't really delete the group, since we are in it. But
408 if (delete && m->cgroup_root)
409 cg_trim(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, false);
411 if (m->pin_cgroupfs_fd >= 0) {
412 close_nointr_nofail(m->pin_cgroupfs_fd);
413 m->pin_cgroupfs_fd = -1;
416 free(m->cgroup_root);
417 m->cgroup_root = NULL;
420 int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding) {
428 b = hashmap_get(m->cgroup_bondings, cgroup);
449 b = hashmap_get(m->cgroup_bondings, p);
457 int cgroup_notify_empty(Manager *m, const char *group) {
458 CGroupBonding *l, *b;
464 r = cgroup_bonding_get(m, group, &l);
468 LIST_FOREACH(by_path, b, l) {
474 t = cgroup_bonding_is_empty_list(b);
477 /* If we don't know, we don't know */
479 log_warning("Failed to check whether cgroup is empty: %s", strerror(errno));
485 /* If it is empty, let's delete it */
486 cgroup_bonding_trim_list(b->unit->cgroup_bondings, true);
488 if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
489 UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
496 Unit* cgroup_unit_by_pid(Manager *m, pid_t pid) {
497 CGroupBonding *l, *b;
505 if (cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0)
508 l = hashmap_get(m->cgroup_bondings, group);
513 while ((slash = strrchr(group, '/'))) {
519 if ((l = hashmap_get(m->cgroup_bondings, group)))
526 LIST_FOREACH(by_path, b, l) {
538 CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) {
542 controller = SYSTEMD_CGROUP_CONTROLLER;
544 LIST_FOREACH(by_unit, b, first)
545 if (streq(b->controller, controller))
551 char *cgroup_bonding_to_string(CGroupBonding *b) {
556 if (asprintf(&r, "%s:%s", b->controller, b->path) < 0)
562 pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) {
564 pid_t pid = 0, npid, mypid;
571 if (cg_enumerate_processes(b->controller, b->path, &f) < 0)
576 while (cg_read_pid(f, &npid) > 0) {
582 /* Ignore processes that aren't our kids */
583 if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
587 /* Dang, there's more than one daemonized PID
588 in this group, so we don't know what process
589 is the main process. */
602 pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *first) {
606 /* Try to find a main pid from this cgroup, but checking if
607 * there's only one PID in the cgroup and returning it. Later
608 * on we might want to add additional, smarter heuristics
611 LIST_FOREACH(by_unit, b, first)
612 if ((pid = cgroup_bonding_search_main_pid(b)) != 0)