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"
35 int cgroup_bonding_realize(CGroupBonding *b) {
40 assert(b->controller);
42 r = cg_create(b->controller, b->path);
44 log_warning("Failed to create cgroup %s:%s: %s", b->controller, b->path, strerror(-r));
53 int cgroup_bonding_realize_list(CGroupBonding *first) {
57 LIST_FOREACH(by_unit, b, first)
58 if ((r = cgroup_bonding_realize(b)) < 0 && b->essential)
64 void cgroup_bonding_free(CGroupBonding *b, bool trim) {
70 LIST_REMOVE(CGroupBonding, by_unit, b->unit->cgroup_bondings, b);
72 if (streq(b->controller, SYSTEMD_CGROUP_CONTROLLER)) {
73 assert_se(f = hashmap_get(b->unit->manager->cgroup_bondings, b->path));
74 LIST_REMOVE(CGroupBonding, by_path, f, b);
77 hashmap_replace(b->unit->manager->cgroup_bondings, b->path, f);
79 hashmap_remove(b->unit->manager->cgroup_bondings, b->path);
83 if (b->realized && b->ours && trim)
84 cg_trim(b->controller, b->path, false);
91 void cgroup_bonding_free_list(CGroupBonding *first, bool remove_or_trim) {
94 LIST_FOREACH_SAFE(by_unit, b, n, first)
95 cgroup_bonding_free(b, remove_or_trim);
98 void cgroup_bonding_trim(CGroupBonding *b, bool delete_root) {
101 if (b->realized && b->ours)
102 cg_trim(b->controller, b->path, delete_root);
105 void cgroup_bonding_trim_list(CGroupBonding *first, bool delete_root) {
108 LIST_FOREACH(by_unit, b, first)
109 cgroup_bonding_trim(b, delete_root);
113 int cgroup_bonding_install(CGroupBonding *b, pid_t pid, const char *cgroup_suffix) {
122 p = join(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_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid) {
159 return cg_set_group_access(b->controller, b->path, mode, uid, gid);
162 int cgroup_bonding_set_group_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid) {
166 LIST_FOREACH(by_unit, b, first) {
167 r = cgroup_bonding_set_group_access(b, mode, uid, gid);
175 int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky) {
181 return cg_set_task_access(b->controller, b->path, mode, uid, gid, sticky);
184 int cgroup_bonding_set_task_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid, int sticky) {
188 LIST_FOREACH(by_unit, b, first) {
189 r = cgroup_bonding_set_task_access(b, mode, uid, gid, sticky);
197 int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, Set *s, const char *cgroup_suffix) {
205 /* Don't kill cgroups that aren't ours */
210 p = join(b->path, "/", cgroup_suffix, NULL);
218 r = cg_kill_recursive(b->controller, path, sig, sigcont, true, false, s);
224 int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, Set *s, const char *cgroup_suffix) {
226 Set *allocated_set = NULL;
227 int ret = -EAGAIN, r;
233 if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
236 LIST_FOREACH(by_unit, b, first) {
237 r = cgroup_bonding_kill(b, sig, sigcont, s, cgroup_suffix);
239 if (r == -EAGAIN || r == -ESRCH)
246 if (ret < 0 || r > 0)
252 set_free(allocated_set);
257 /* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we
259 int cgroup_bonding_is_empty(CGroupBonding *b) {
264 if ((r = cg_is_empty_recursive(b->controller, b->path, true)) < 0)
267 /* If it is empty it is empty */
271 /* It's not only us using this cgroup, so we just don't know */
272 return b->ours ? 0 : -EAGAIN;
275 int cgroup_bonding_is_empty_list(CGroupBonding *first) {
278 LIST_FOREACH(by_unit, b, first) {
281 if ((r = cgroup_bonding_is_empty(b)) < 0) {
282 /* If this returned -EAGAIN, then we don't know if the
283 * group is empty, so let's see if another group can
295 int manager_setup_cgroup(Manager *m) {
296 char *current = NULL, *path = NULL;
302 /* 0. Be nice to Ingo Molnar #628004 */
303 if (path_is_mount_point("/sys/fs/cgroup/systemd", false) <= 0) {
304 log_warning("No control group support available, not creating root group.");
308 /* 1. Determine hierarchy */
309 r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, ¤t);
311 log_error("Cannot determine cgroup we are running in: %s", strerror(-r));
315 if (m->running_as == MANAGER_SYSTEM)
316 strcpy(suffix, "/system");
318 snprintf(suffix, sizeof(suffix), "/systemd-%lu", (unsigned long) getpid());
319 char_array_0(suffix);
322 free(m->cgroup_hierarchy);
323 if (endswith(current, suffix)) {
324 /* We probably got reexecuted and can continue to use our root cgroup */
325 m->cgroup_hierarchy = current;
329 /* We need a new root cgroup */
330 m->cgroup_hierarchy = NULL;
331 if (asprintf(&m->cgroup_hierarchy, "%s%s", streq(current, "/") ? "" : current, suffix) < 0) {
332 log_error("Out of memory");
339 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path);
341 log_error("Cannot find cgroup mount point: %s", strerror(-r));
345 log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
347 /* 3. Install agent */
348 r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH);
350 log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
352 log_debug("Installed release agent.");
354 log_debug("Release agent already installed.");
356 /* 4. Realize the group */
357 r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, 0);
359 log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
363 /* 5. And pin it, so that it cannot be unmounted */
364 if (m->pin_cgroupfs_fd >= 0)
365 close_nointr_nofail(m->pin_cgroupfs_fd);
367 m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
369 log_error("Failed to open pin file: %m");
374 log_debug("Created root group.");
376 cg_shorten_controllers(m->default_controllers);
385 void manager_shutdown_cgroup(Manager *m, bool delete) {
388 if (delete && m->cgroup_hierarchy)
389 cg_delete(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy);
391 if (m->pin_cgroupfs_fd >= 0) {
392 close_nointr_nofail(m->pin_cgroupfs_fd);
393 m->pin_cgroupfs_fd = -1;
396 free(m->cgroup_hierarchy);
397 m->cgroup_hierarchy = NULL;
400 int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding) {
408 b = hashmap_get(m->cgroup_bondings, cgroup);
430 b = hashmap_get(m->cgroup_bondings, p);
439 int cgroup_notify_empty(Manager *m, const char *group) {
440 CGroupBonding *l, *b;
446 r = cgroup_bonding_get(m, group, &l);
450 LIST_FOREACH(by_path, b, l) {
456 t = cgroup_bonding_is_empty_list(b);
459 /* If we don't know, we don't know */
461 log_warning("Failed to check whether cgroup is empty: %s", strerror(errno));
467 /* If it is empty, let's delete it */
468 cgroup_bonding_trim_list(b->unit->cgroup_bondings, true);
470 if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
471 UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
478 Unit* cgroup_unit_by_pid(Manager *m, pid_t pid) {
479 CGroupBonding *l, *b;
487 if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0)
490 l = hashmap_get(m->cgroup_bondings, group);
495 while ((slash = strrchr(group, '/'))) {
501 if ((l = hashmap_get(m->cgroup_bondings, group)))
508 LIST_FOREACH(by_path, b, l) {
520 CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) {
525 LIST_FOREACH(by_unit, b, first)
526 if (streq(b->controller, controller))
532 char *cgroup_bonding_to_string(CGroupBonding *b) {
537 if (asprintf(&r, "%s:%s", b->controller, b->path) < 0)
543 pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) {
545 pid_t pid = 0, npid, mypid;
552 if (cg_enumerate_processes(b->controller, b->path, &f) < 0)
557 while (cg_read_pid(f, &npid) > 0) {
563 /* Ignore processes that aren't our kids */
564 if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
568 /* Dang, there's more than one daemonized PID
569 in this group, so we don't know what process
570 is the main process. */
583 pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *first) {
587 /* Try to find a main pid from this cgroup, but checking if
588 * there's only one PID in the cgroup and returning it. Later
589 * on we might want to add additional, smarter heuristics
592 LIST_FOREACH(by_unit, b, first)
593 if ((pid = cgroup_bonding_search_main_pid(b)) != 0)