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 int cgroup_bonding_realize(CGroupBonding *b) {
39 assert(b->controller);
41 r = cg_create(b->controller, b->path);
43 log_warning("Failed to create cgroup %s:%s: %s", b->controller, b->path, strerror(-r));
52 int cgroup_bonding_realize_list(CGroupBonding *first) {
56 LIST_FOREACH(by_unit, b, first)
57 if ((r = cgroup_bonding_realize(b)) < 0 && b->essential)
63 void cgroup_bonding_free(CGroupBonding *b, bool trim) {
69 LIST_REMOVE(CGroupBonding, by_unit, b->unit->cgroup_bondings, b);
71 if (streq(b->controller, SYSTEMD_CGROUP_CONTROLLER)) {
72 assert_se(f = hashmap_get(b->unit->manager->cgroup_bondings, b->path));
73 LIST_REMOVE(CGroupBonding, by_path, f, b);
76 hashmap_replace(b->unit->manager->cgroup_bondings, b->path, f);
78 hashmap_remove(b->unit->manager->cgroup_bondings, b->path);
82 if (b->realized && b->ours && trim)
83 cg_trim(b->controller, b->path, false);
90 void cgroup_bonding_free_list(CGroupBonding *first, bool remove_or_trim) {
93 LIST_FOREACH_SAFE(by_unit, b, n, first)
94 cgroup_bonding_free(b, remove_or_trim);
97 void cgroup_bonding_trim(CGroupBonding *b, bool delete_root) {
100 if (b->realized && b->ours)
101 cg_trim(b->controller, b->path, delete_root);
104 void cgroup_bonding_trim_list(CGroupBonding *first, bool delete_root) {
107 LIST_FOREACH(by_unit, b, first)
108 cgroup_bonding_trim(b, delete_root);
112 int cgroup_bonding_install(CGroupBonding *b, pid_t pid, const char *cgroup_suffix) {
121 p = join(b->path, "/", cgroup_suffix, NULL);
129 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_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid) {
158 return cg_set_group_access(b->controller, b->path, mode, uid, gid);
161 int cgroup_bonding_set_group_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid) {
165 LIST_FOREACH(by_unit, b, first) {
166 r = cgroup_bonding_set_group_access(b, mode, uid, gid);
174 int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky) {
180 return cg_set_task_access(b->controller, b->path, mode, uid, gid, sticky);
183 int cgroup_bonding_set_task_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid, int sticky) {
187 LIST_FOREACH(by_unit, b, first) {
188 r = cgroup_bonding_set_task_access(b, mode, uid, gid, sticky);
196 int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, Set *s, const char *cgroup_suffix) {
204 /* Don't kill cgroups that aren't ours */
209 p = join(b->path, "/", cgroup_suffix, NULL);
217 r = cg_kill_recursive(b->controller, path, sig, sigcont, true, false, s);
223 int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, Set *s, const char *cgroup_suffix) {
225 Set *allocated_set = NULL;
226 int ret = -EAGAIN, r;
232 if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
235 LIST_FOREACH(by_unit, b, first) {
236 r = cgroup_bonding_kill(b, sig, sigcont, s, cgroup_suffix);
238 if (r == -EAGAIN || r == -ESRCH)
245 if (ret < 0 || r > 0)
251 set_free(allocated_set);
256 /* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we
258 int cgroup_bonding_is_empty(CGroupBonding *b) {
263 if ((r = cg_is_empty_recursive(b->controller, b->path, true)) < 0)
266 /* If it is empty it is empty */
270 /* It's not only us using this cgroup, so we just don't know */
271 return b->ours ? 0 : -EAGAIN;
274 int cgroup_bonding_is_empty_list(CGroupBonding *first) {
277 LIST_FOREACH(by_unit, b, first) {
280 if ((r = cgroup_bonding_is_empty(b)) < 0) {
281 /* If this returned -EAGAIN, then we don't know if the
282 * group is empty, so let's see if another group can
294 int manager_setup_cgroup(Manager *m) {
295 char *current = NULL, *path = NULL;
301 /* 0. Be nice to Ingo Molnar #628004 */
302 if (path_is_mount_point("/sys/fs/cgroup/systemd", false) <= 0) {
303 log_warning("No control group support available, not creating root group.");
307 /* 1. Determine hierarchy */
308 if ((r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, ¤t)) < 0) {
309 log_error("Cannot determine cgroup we are running in: %s", strerror(-r));
313 if (m->running_as == MANAGER_SYSTEM)
314 strcpy(suffix, "/system");
316 snprintf(suffix, sizeof(suffix), "/systemd-%lu", (unsigned long) getpid());
317 char_array_0(suffix);
320 free(m->cgroup_hierarchy);
321 if (endswith(current, suffix)) {
322 /* We probably got reexecuted and can continue to use our root cgroup */
323 m->cgroup_hierarchy = current;
327 /* We need a new root cgroup */
328 m->cgroup_hierarchy = NULL;
329 if (asprintf(&m->cgroup_hierarchy, "%s%s", streq(current, "/") ? "" : current, suffix) < 0) {
330 log_error("Out of memory");
337 if ((r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path)) < 0) {
338 log_error("Cannot find cgroup mount point: %s", strerror(-r));
342 log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
344 /* 3. Install agent */
345 if ((r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH)) < 0)
346 log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
348 log_debug("Installed release agent.");
350 log_debug("Release agent already installed.");
352 /* 4. Realize the group */
353 if ((r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, 0)) < 0) {
354 log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
358 /* 5. And pin it, so that it cannot be unmounted */
359 if (m->pin_cgroupfs_fd >= 0)
360 close_nointr_nofail(m->pin_cgroupfs_fd);
362 if ((m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK)) < 0) {
363 log_error("Failed to open pin file: %m");
368 log_debug("Created root group.");
377 void manager_shutdown_cgroup(Manager *m, bool delete) {
380 if (delete && m->cgroup_hierarchy)
381 cg_delete(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy);
383 if (m->pin_cgroupfs_fd >= 0) {
384 close_nointr_nofail(m->pin_cgroupfs_fd);
385 m->pin_cgroupfs_fd = -1;
388 free(m->cgroup_hierarchy);
389 m->cgroup_hierarchy = NULL;
392 int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding) {
400 b = hashmap_get(m->cgroup_bondings, cgroup);
422 b = hashmap_get(m->cgroup_bondings, p);
431 int cgroup_notify_empty(Manager *m, const char *group) {
432 CGroupBonding *l, *b;
438 r = cgroup_bonding_get(m, group, &l);
442 LIST_FOREACH(by_path, b, l) {
448 t = cgroup_bonding_is_empty_list(b);
451 /* If we don't know, we don't know */
453 log_warning("Failed to check whether cgroup is empty: %s", strerror(errno));
459 /* If it is empty, let's delete it */
460 cgroup_bonding_trim_list(b->unit->cgroup_bondings, true);
462 if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
463 UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
470 Unit* cgroup_unit_by_pid(Manager *m, pid_t pid) {
471 CGroupBonding *l, *b;
479 if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0)
482 l = hashmap_get(m->cgroup_bondings, group);
487 while ((slash = strrchr(group, '/'))) {
493 if ((l = hashmap_get(m->cgroup_bondings, group)))
500 LIST_FOREACH(by_path, b, l) {
512 CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) {
517 LIST_FOREACH(by_unit, b, first)
518 if (streq(b->controller, controller))
524 char *cgroup_bonding_to_string(CGroupBonding *b) {
529 if (asprintf(&r, "%s:%s", b->controller, b->path) < 0)
535 pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) {
537 pid_t pid = 0, npid, mypid;
544 if (cg_enumerate_processes(b->controller, b->path, &f) < 0)
549 while (cg_read_pid(f, &npid) > 0) {
555 /* Ignore processes that aren't our kids */
556 if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
560 /* Dang, there's more than one daemonized PID
561 in this group, so we don't know what process
562 is the main process. */
575 pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *first) {
579 /* Try to find a main pid from this cgroup, but checking if
580 * there's only one PID in the cgroup and returning it. Later
581 * on we might want to add additional, smarter heuristics
584 LIST_FOREACH(by_unit, b, first)
585 if ((pid = cgroup_bonding_search_main_pid(b)) != 0)