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);
111 int cgroup_bonding_install(CGroupBonding *b, pid_t pid) {
117 if ((r = cg_create_and_attach(b->controller, b->path, pid)) < 0)
124 int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid) {
128 LIST_FOREACH(by_unit, b, first)
129 if ((r = cgroup_bonding_install(b, pid)) < 0 && b->essential)
135 int cgroup_bonding_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid) {
141 return cg_set_group_access(b->controller, b->path, mode, uid, gid);
144 int cgroup_bonding_set_group_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid) {
148 LIST_FOREACH(by_unit, b, first) {
149 r = cgroup_bonding_set_group_access(b, mode, uid, gid);
157 int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky) {
163 return cg_set_task_access(b->controller, b->path, mode, uid, gid, sticky);
166 int cgroup_bonding_set_task_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid, int sticky) {
170 LIST_FOREACH(by_unit, b, first) {
171 r = cgroup_bonding_set_task_access(b, mode, uid, gid, sticky);
179 int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, Set *s) {
183 /* Don't kill cgroups that aren't ours */
187 return cg_kill_recursive(b->controller, b->path, sig, sigcont, true, false, s);
190 int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, Set *s) {
192 Set *allocated_set = NULL;
193 int ret = -EAGAIN, r;
199 if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
202 LIST_FOREACH(by_unit, b, first) {
203 if ((r = cgroup_bonding_kill(b, sig, sigcont, s)) < 0) {
204 if (r == -EAGAIN || r == -ESRCH)
211 if (ret < 0 || r > 0)
217 set_free(allocated_set);
222 /* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we
224 int cgroup_bonding_is_empty(CGroupBonding *b) {
229 if ((r = cg_is_empty_recursive(b->controller, b->path, true)) < 0)
232 /* If it is empty it is empty */
236 /* It's not only us using this cgroup, so we just don't know */
237 return b->ours ? 0 : -EAGAIN;
240 int cgroup_bonding_is_empty_list(CGroupBonding *first) {
243 LIST_FOREACH(by_unit, b, first) {
246 if ((r = cgroup_bonding_is_empty(b)) < 0) {
247 /* If this returned -EAGAIN, then we don't know if the
248 * group is empty, so let's see if another group can
260 int manager_setup_cgroup(Manager *m) {
261 char *current = NULL, *path = NULL;
267 /* 0. Be nice to Ingo Molnar #628004 */
268 if (path_is_mount_point("/sys/fs/cgroup/systemd", false) <= 0) {
269 log_warning("No control group support available, not creating root group.");
273 /* 1. Determine hierarchy */
274 if ((r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, ¤t)) < 0) {
275 log_error("Cannot determine cgroup we are running in: %s", strerror(-r));
279 if (m->running_as == MANAGER_SYSTEM)
280 strcpy(suffix, "/system");
282 snprintf(suffix, sizeof(suffix), "/systemd-%lu", (unsigned long) getpid());
283 char_array_0(suffix);
286 free(m->cgroup_hierarchy);
287 if (endswith(current, suffix)) {
288 /* We probably got reexecuted and can continue to use our root cgroup */
289 m->cgroup_hierarchy = current;
293 /* We need a new root cgroup */
294 m->cgroup_hierarchy = NULL;
295 if (asprintf(&m->cgroup_hierarchy, "%s%s", streq(current, "/") ? "" : current, suffix) < 0) {
296 log_error("Out of memory");
303 if ((r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path)) < 0) {
304 log_error("Cannot find cgroup mount point: %s", strerror(-r));
308 log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
310 /* 3. Install agent */
311 if ((r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH)) < 0)
312 log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
314 log_debug("Installed release agent.");
316 log_debug("Release agent already installed.");
318 /* 4. Realize the group */
319 if ((r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, 0)) < 0) {
320 log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
324 /* 5. And pin it, so that it cannot be unmounted */
325 if (m->pin_cgroupfs_fd >= 0)
326 close_nointr_nofail(m->pin_cgroupfs_fd);
328 if ((m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK)) < 0) {
329 log_error("Failed to open pin file: %m");
334 log_debug("Created root group.");
343 void manager_shutdown_cgroup(Manager *m, bool delete) {
346 if (delete && m->cgroup_hierarchy)
347 cg_delete(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy);
349 if (m->pin_cgroupfs_fd >= 0) {
350 close_nointr_nofail(m->pin_cgroupfs_fd);
351 m->pin_cgroupfs_fd = -1;
354 free(m->cgroup_hierarchy);
355 m->cgroup_hierarchy = NULL;
358 int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding) {
366 b = hashmap_get(m->cgroup_bondings, cgroup);
388 b = hashmap_get(m->cgroup_bondings, p);
397 int cgroup_notify_empty(Manager *m, const char *group) {
398 CGroupBonding *l, *b;
404 r = cgroup_bonding_get(m, group, &l);
408 LIST_FOREACH(by_path, b, l) {
414 t = cgroup_bonding_is_empty_list(b);
417 /* If we don't know, we don't know */
419 log_warning("Failed to check whether cgroup is empty: %s", strerror(errno));
425 /* If it is empty, let's delete it */
426 cgroup_bonding_trim_list(b->unit->cgroup_bondings, true);
428 if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
429 UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
436 Unit* cgroup_unit_by_pid(Manager *m, pid_t pid) {
437 CGroupBonding *l, *b;
445 if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0)
448 l = hashmap_get(m->cgroup_bondings, group);
453 while ((slash = strrchr(group, '/'))) {
459 if ((l = hashmap_get(m->cgroup_bondings, group)))
466 LIST_FOREACH(by_path, b, l) {
478 CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) {
483 LIST_FOREACH(by_unit, b, first)
484 if (streq(b->controller, controller))
490 char *cgroup_bonding_to_string(CGroupBonding *b) {
495 if (asprintf(&r, "%s:%s", b->controller, b->path) < 0)
501 pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) {
503 pid_t pid = 0, npid, mypid;
510 if (cg_enumerate_processes(b->controller, b->path, &f) < 0)
515 while (cg_read_pid(f, &npid) > 0) {
521 /* Ignore processes that aren't our kids */
522 if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
526 /* Dang, there's more than one daemonized PID
527 in this group, so we don't know what process
528 is the main process. */
541 pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *first) {
545 /* Try to find a main pid from this cgroup, but checking if
546 * there's only one PID in the cgroup and returning it. Later
547 * on we might want to add additional, smarter heuristics
550 LIST_FOREACH(by_unit, b, first)
551 if ((pid = cgroup_bonding_search_main_pid(b)) != 0)