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"
36 int cgroup_bonding_realize(CGroupBonding *b) {
41 assert(b->controller);
43 r = cg_create(b->controller, b->path);
45 log_warning("Failed to create cgroup %s:%s: %s", b->controller, b->path, strerror(-r));
54 int cgroup_bonding_realize_list(CGroupBonding *first) {
58 LIST_FOREACH(by_unit, b, first)
59 if ((r = cgroup_bonding_realize(b)) < 0 && b->essential)
65 void cgroup_bonding_free(CGroupBonding *b, bool trim) {
71 LIST_REMOVE(CGroupBonding, by_unit, b->unit->cgroup_bondings, b);
73 if (streq(b->controller, SYSTEMD_CGROUP_CONTROLLER)) {
74 assert_se(f = hashmap_get(b->unit->manager->cgroup_bondings, b->path));
75 LIST_REMOVE(CGroupBonding, by_path, f, b);
78 hashmap_replace(b->unit->manager->cgroup_bondings, b->path, f);
80 hashmap_remove(b->unit->manager->cgroup_bondings, b->path);
84 if (b->realized && b->ours && trim)
85 cg_trim(b->controller, b->path, false);
92 void cgroup_bonding_free_list(CGroupBonding *first, bool remove_or_trim) {
95 LIST_FOREACH_SAFE(by_unit, b, n, first)
96 cgroup_bonding_free(b, remove_or_trim);
99 void cgroup_bonding_trim(CGroupBonding *b, bool delete_root) {
102 if (b->realized && b->ours)
103 cg_trim(b->controller, b->path, delete_root);
106 void cgroup_bonding_trim_list(CGroupBonding *first, bool delete_root) {
109 LIST_FOREACH(by_unit, b, first)
110 cgroup_bonding_trim(b, delete_root);
113 int cgroup_bonding_install(CGroupBonding *b, pid_t pid, const char *cgroup_suffix) {
122 p = strjoin(b->path, "/", cgroup_suffix, NULL);
130 r = cg_create_and_attach(b->controller, path, pid);
140 int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid, const char *cgroup_suffix) {
144 LIST_FOREACH(by_unit, b, first) {
145 r = cgroup_bonding_install(b, pid, cgroup_suffix);
146 if (r < 0 && b->essential)
153 int cgroup_bonding_migrate(CGroupBonding *b, CGroupBonding *list) {
157 LIST_FOREACH(by_unit, q, list) {
166 r = cg_migrate_recursive(q->controller, q->path, b->controller, b->path, true, false);
167 if (r < 0 && ret == 0)
174 int cgroup_bonding_migrate_to(CGroupBonding *b, const char *target, bool rem) {
178 return cg_migrate_recursive(b->controller, b->path, b->controller, target, true, rem);
181 int cgroup_bonding_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid) {
187 return cg_set_group_access(b->controller, b->path, mode, uid, gid);
190 int cgroup_bonding_set_group_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid) {
194 LIST_FOREACH(by_unit, b, first) {
195 r = cgroup_bonding_set_group_access(b, mode, uid, gid);
203 int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky) {
209 return cg_set_task_access(b->controller, b->path, mode, uid, gid, sticky);
212 int cgroup_bonding_set_task_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid, int sticky) {
216 LIST_FOREACH(by_unit, b, first) {
217 r = cgroup_bonding_set_task_access(b, mode, uid, gid, sticky);
225 int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, bool rem, Set *s, const char *cgroup_suffix) {
233 /* Don't kill cgroups that aren't ours */
238 p = strjoin(b->path, "/", cgroup_suffix, NULL);
246 r = cg_kill_recursive(b->controller, path, sig, sigcont, true, rem, s);
252 int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, bool rem, Set *s, const char *cgroup_suffix) {
254 Set *allocated_set = NULL;
255 int ret = -EAGAIN, r;
261 if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
264 LIST_FOREACH(by_unit, b, first) {
265 r = cgroup_bonding_kill(b, sig, sigcont, rem, s, cgroup_suffix);
267 if (r == -EAGAIN || r == -ESRCH)
274 if (ret < 0 || r > 0)
280 set_free(allocated_set);
285 /* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we
287 int cgroup_bonding_is_empty(CGroupBonding *b) {
292 if ((r = cg_is_empty_recursive(b->controller, b->path, true)) < 0)
295 /* If it is empty it is empty */
299 /* It's not only us using this cgroup, so we just don't know */
300 return b->ours ? 0 : -EAGAIN;
303 int cgroup_bonding_is_empty_list(CGroupBonding *first) {
306 LIST_FOREACH(by_unit, b, first) {
309 if ((r = cgroup_bonding_is_empty(b)) < 0) {
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 char *current = NULL, *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 r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, ¤t);
339 log_error("Cannot determine cgroup we are running in: %s", strerror(-r));
343 if (m->running_as == SYSTEMD_SYSTEM)
344 strcpy(suffix, "/system");
346 snprintf(suffix, sizeof(suffix), "/systemd-%lu", (unsigned long) getpid());
347 char_array_0(suffix);
350 free(m->cgroup_hierarchy);
351 if (endswith(current, suffix)) {
352 /* We probably got reexecuted and can continue to use our root cgroup */
353 m->cgroup_hierarchy = current;
357 /* We need a new root cgroup */
358 m->cgroup_hierarchy = NULL;
359 if (asprintf(&m->cgroup_hierarchy, "%s%s", streq(current, "/") ? "" : current, suffix) < 0) {
366 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path);
368 log_error("Cannot find cgroup mount point: %s", strerror(-r));
372 log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
374 /* 3. Install agent */
375 r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH);
377 log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
379 log_debug("Installed release agent.");
381 log_debug("Release agent already installed.");
383 /* 4. Realize the group */
384 r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, 0);
386 log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
390 /* 5. And pin it, so that it cannot be unmounted */
391 if (m->pin_cgroupfs_fd >= 0)
392 close_nointr_nofail(m->pin_cgroupfs_fd);
394 m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
396 log_error("Failed to open pin file: %m");
401 log_debug("Created root group.");
403 cg_shorten_controllers(m->default_controllers);
412 void manager_shutdown_cgroup(Manager *m, bool delete) {
415 if (delete && m->cgroup_hierarchy)
416 cg_delete(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy);
418 if (m->pin_cgroupfs_fd >= 0) {
419 close_nointr_nofail(m->pin_cgroupfs_fd);
420 m->pin_cgroupfs_fd = -1;
423 free(m->cgroup_hierarchy);
424 m->cgroup_hierarchy = NULL;
427 int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding) {
435 b = hashmap_get(m->cgroup_bondings, cgroup);
457 b = hashmap_get(m->cgroup_bondings, p);
466 int cgroup_notify_empty(Manager *m, const char *group) {
467 CGroupBonding *l, *b;
473 r = cgroup_bonding_get(m, group, &l);
477 LIST_FOREACH(by_path, b, l) {
483 t = cgroup_bonding_is_empty_list(b);
486 /* If we don't know, we don't know */
488 log_warning("Failed to check whether cgroup is empty: %s", strerror(errno));
494 /* If it is empty, let's delete it */
495 cgroup_bonding_trim_list(b->unit->cgroup_bondings, true);
497 if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
498 UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
505 Unit* cgroup_unit_by_pid(Manager *m, pid_t pid) {
506 CGroupBonding *l, *b;
514 if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0)
517 l = hashmap_get(m->cgroup_bondings, group);
522 while ((slash = strrchr(group, '/'))) {
528 if ((l = hashmap_get(m->cgroup_bondings, group)))
535 LIST_FOREACH(by_path, b, l) {
547 CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) {
551 controller = SYSTEMD_CGROUP_CONTROLLER;
553 LIST_FOREACH(by_unit, b, first)
554 if (streq(b->controller, controller))
560 char *cgroup_bonding_to_string(CGroupBonding *b) {
565 if (asprintf(&r, "%s:%s", b->controller, b->path) < 0)
571 pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) {
573 pid_t pid = 0, npid, mypid;
580 if (cg_enumerate_processes(b->controller, b->path, &f) < 0)
585 while (cg_read_pid(f, &npid) > 0) {
591 /* Ignore processes that aren't our kids */
592 if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
596 /* Dang, there's more than one daemonized PID
597 in this group, so we don't know what process
598 is the main process. */
611 pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *first) {
615 /* Try to find a main pid from this cgroup, but checking if
616 * there's only one PID in the cgroup and returning it. Later
617 * on we might want to add additional, smarter heuristics
620 LIST_FOREACH(by_unit, b, first)
621 if ((pid = cgroup_bonding_search_main_pid(b)) != 0)