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);
114 int cgroup_bonding_install(CGroupBonding *b, pid_t pid, const char *cgroup_suffix) {
123 p = join(b->path, "/", cgroup_suffix, NULL);
131 r = cg_create_and_attach(b->controller, path, pid);
141 int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid, const char *cgroup_suffix) {
145 LIST_FOREACH(by_unit, b, first) {
146 r = cgroup_bonding_install(b, pid, cgroup_suffix);
147 if (r < 0 && b->essential)
154 int cgroup_bonding_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid) {
160 return cg_set_group_access(b->controller, b->path, mode, uid, gid);
163 int cgroup_bonding_set_group_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid) {
167 LIST_FOREACH(by_unit, b, first) {
168 r = cgroup_bonding_set_group_access(b, mode, uid, gid);
176 int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky) {
182 return cg_set_task_access(b->controller, b->path, mode, uid, gid, sticky);
185 int cgroup_bonding_set_task_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid, int sticky) {
189 LIST_FOREACH(by_unit, b, first) {
190 r = cgroup_bonding_set_task_access(b, mode, uid, gid, sticky);
198 int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, bool rem, Set *s, const char *cgroup_suffix) {
206 /* Don't kill cgroups that aren't ours */
211 p = join(b->path, "/", cgroup_suffix, NULL);
219 r = cg_kill_recursive(b->controller, path, sig, sigcont, true, rem, s);
225 int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, bool rem, Set *s, const char *cgroup_suffix) {
227 Set *allocated_set = NULL;
228 int ret = -EAGAIN, r;
234 if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
237 LIST_FOREACH(by_unit, b, first) {
238 r = cgroup_bonding_kill(b, sig, sigcont, rem, s, cgroup_suffix);
240 if (r == -EAGAIN || r == -ESRCH)
247 if (ret < 0 || r > 0)
253 set_free(allocated_set);
258 /* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we
260 int cgroup_bonding_is_empty(CGroupBonding *b) {
265 if ((r = cg_is_empty_recursive(b->controller, b->path, true)) < 0)
268 /* If it is empty it is empty */
272 /* It's not only us using this cgroup, so we just don't know */
273 return b->ours ? 0 : -EAGAIN;
276 int cgroup_bonding_is_empty_list(CGroupBonding *first) {
279 LIST_FOREACH(by_unit, b, first) {
282 if ((r = cgroup_bonding_is_empty(b)) < 0) {
283 /* If this returned -EAGAIN, then we don't know if the
284 * group is empty, so let's see if another group can
296 int manager_setup_cgroup(Manager *m) {
297 char *current = NULL, *path = NULL;
303 /* 0. Be nice to Ingo Molnar #628004 */
304 if (path_is_mount_point("/sys/fs/cgroup/systemd", false) <= 0) {
305 log_warning("No control group support available, not creating root group.");
309 /* 1. Determine hierarchy */
310 r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, ¤t);
312 log_error("Cannot determine cgroup we are running in: %s", strerror(-r));
316 if (m->running_as == MANAGER_SYSTEM)
317 strcpy(suffix, "/system");
319 snprintf(suffix, sizeof(suffix), "/systemd-%lu", (unsigned long) getpid());
320 char_array_0(suffix);
323 free(m->cgroup_hierarchy);
324 if (endswith(current, suffix)) {
325 /* We probably got reexecuted and can continue to use our root cgroup */
326 m->cgroup_hierarchy = current;
330 /* We need a new root cgroup */
331 m->cgroup_hierarchy = NULL;
332 if (asprintf(&m->cgroup_hierarchy, "%s%s", streq(current, "/") ? "" : current, suffix) < 0) {
333 log_error("Out of memory");
340 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path);
342 log_error("Cannot find cgroup mount point: %s", strerror(-r));
346 log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
348 /* 3. Install agent */
349 r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH);
351 log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
353 log_debug("Installed release agent.");
355 log_debug("Release agent already installed.");
357 /* 4. Realize the group */
358 r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, 0);
360 log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
364 /* 5. And pin it, so that it cannot be unmounted */
365 if (m->pin_cgroupfs_fd >= 0)
366 close_nointr_nofail(m->pin_cgroupfs_fd);
368 m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
370 log_error("Failed to open pin file: %m");
375 log_debug("Created root group.");
377 cg_shorten_controllers(m->default_controllers);
386 void manager_shutdown_cgroup(Manager *m, bool delete) {
389 if (delete && m->cgroup_hierarchy)
390 cg_delete(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy);
392 if (m->pin_cgroupfs_fd >= 0) {
393 close_nointr_nofail(m->pin_cgroupfs_fd);
394 m->pin_cgroupfs_fd = -1;
397 free(m->cgroup_hierarchy);
398 m->cgroup_hierarchy = NULL;
401 int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding) {
409 b = hashmap_get(m->cgroup_bondings, cgroup);
431 b = hashmap_get(m->cgroup_bondings, p);
440 int cgroup_notify_empty(Manager *m, const char *group) {
441 CGroupBonding *l, *b;
447 r = cgroup_bonding_get(m, group, &l);
451 LIST_FOREACH(by_path, b, l) {
457 t = cgroup_bonding_is_empty_list(b);
460 /* If we don't know, we don't know */
462 log_warning("Failed to check whether cgroup is empty: %s", strerror(errno));
468 /* If it is empty, let's delete it */
469 cgroup_bonding_trim_list(b->unit->cgroup_bondings, true);
471 if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
472 UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
479 Unit* cgroup_unit_by_pid(Manager *m, pid_t pid) {
480 CGroupBonding *l, *b;
488 if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0)
491 l = hashmap_get(m->cgroup_bondings, group);
496 while ((slash = strrchr(group, '/'))) {
502 if ((l = hashmap_get(m->cgroup_bondings, group)))
509 LIST_FOREACH(by_path, b, l) {
521 CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) {
526 LIST_FOREACH(by_unit, b, first)
527 if (streq(b->controller, controller))
533 char *cgroup_bonding_to_string(CGroupBonding *b) {
538 if (asprintf(&r, "%s:%s", b->controller, b->path) < 0)
544 pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) {
546 pid_t pid = 0, npid, mypid;
553 if (cg_enumerate_processes(b->controller, b->path, &f) < 0)
558 while (cg_read_pid(f, &npid) > 0) {
564 /* Ignore processes that aren't our kids */
565 if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
569 /* Dang, there's more than one daemonized PID
570 in this group, so we don't know what process
571 is the main process. */
584 pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *first) {
588 /* Try to find a main pid from this cgroup, but checking if
589 * there's only one PID in the cgroup and returning it. Later
590 * on we might want to add additional, smarter heuristics
593 LIST_FOREACH(by_unit, b, first)
594 if ((pid = cgroup_bonding_search_main_pid(b)) != 0)