diff options
author | Lennart Poettering <lennart@poettering.net> | 2010-05-16 18:45:24 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2010-05-16 18:45:24 +0200 |
commit | e99e38bbdcca3fe5956823bdb3d38544ccf93221 (patch) | |
tree | 109871cf2bdcad19105d55f4eea62d5495a8f614 /cgroup.c | |
parent | e9da3678fcfc774b325dc1eaa054d0e00028a1fc (diff) |
build-sys: move source files to subdirectory
Diffstat (limited to 'cgroup.c')
-rw-r--r-- | cgroup.c | 561 |
1 files changed, 0 insertions, 561 deletions
diff --git a/cgroup.c b/cgroup.c deleted file mode 100644 index 301fc949da..0000000000 --- a/cgroup.c +++ /dev/null @@ -1,561 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8 -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <errno.h> -#include <assert.h> -#include <unistd.h> -#include <sys/types.h> -#include <signal.h> -#include <sys/mount.h> - -#include "cgroup.h" -#include "log.h" - -static int translate_error(int error, int _errno) { - - switch (error) { - - case ECGROUPNOTCOMPILED: - case ECGROUPNOTMOUNTED: - case ECGROUPNOTEXIST: - case ECGROUPNOTCREATED: - return -ENOENT; - - case ECGINVAL: - return -EINVAL; - - case ECGROUPNOTALLOWED: - return -EPERM; - - case ECGOTHER: - return -_errno; - } - - return -EIO; -} - -int cgroup_bonding_realize(CGroupBonding *b) { - int r; - - assert(b); - assert(b->path); - assert(b->controller); - - if (b->cgroup) - return 0; - - if (!(b->cgroup = cgroup_new_cgroup(b->path))) - return -ENOMEM; - - if (!cgroup_add_controller(b->cgroup, b->controller)) { - r = -ENOMEM; - goto fail; - } - - if (b->inherit) - r = cgroup_create_cgroup_from_parent(b->cgroup, true); - else - r = cgroup_create_cgroup(b->cgroup, true); - - if (r != 0) { - r = translate_error(r, errno); - goto fail; - } - - return 0; - -fail: - cgroup_free(&b->cgroup); - b->cgroup = NULL; - return r; -} - -int cgroup_bonding_realize_list(CGroupBonding *first) { - CGroupBonding *b; - - LIST_FOREACH(by_unit, b, first) { - int r; - - if ((r = cgroup_bonding_realize(b)) < 0) - return r; - } - - return 0; -} - -void cgroup_bonding_free(CGroupBonding *b) { - assert(b); - - if (b->unit) { - CGroupBonding *f; - - LIST_REMOVE(CGroupBonding, by_unit, b->unit->meta.cgroup_bondings, b); - - assert_se(f = hashmap_get(b->unit->meta.manager->cgroup_bondings, b->path)); - LIST_REMOVE(CGroupBonding, by_path, f, b); - - if (f) - hashmap_replace(b->unit->meta.manager->cgroup_bondings, b->path, f); - else - hashmap_remove(b->unit->meta.manager->cgroup_bondings, b->path); - } - - if (b->cgroup) { - if (b->only_us && b->clean_up && cgroup_bonding_is_empty(b) > 0) - cgroup_delete_cgroup_ext(b->cgroup, true); - - cgroup_free(&b->cgroup); - } - - free(b->controller); - free(b->path); - free(b); -} - -void cgroup_bonding_free_list(CGroupBonding *first) { - CGroupBonding *b, *n; - - LIST_FOREACH_SAFE(by_unit, b, n, first) - cgroup_bonding_free(b); -} - -int cgroup_bonding_install(CGroupBonding *b, pid_t pid) { - int r; - - assert(b); - assert(pid >= 0); - - if (pid == 0) - pid = getpid(); - - if (!b->cgroup) - return -ENOENT; - - if ((r = cgroup_attach_task_pid(b->cgroup, pid))) - return translate_error(r, errno); - - return 0; -} - -int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid) { - CGroupBonding *b; - - LIST_FOREACH(by_unit, b, first) { - int r; - - if ((r = cgroup_bonding_install(b, pid)) < 0) - return r; - } - - return 0; -} - -int cgroup_bonding_kill(CGroupBonding *b, int sig) { - int r; - Set *s; - bool done; - bool killed = false; - - assert(b); - assert(sig > 0); - - if (!b->only_us) - return -EAGAIN; - - if (!(s = set_new(trivial_hash_func, trivial_compare_func))) - return -ENOMEM; - - do { - void *iterator; - pid_t pid; - - done = true; - - if ((r = cgroup_get_task_begin(b->path, b->controller, &iterator, &pid)) != 0) { - if (r == ECGEOF) { - r = 0; - goto kill_done; - } else { - r = translate_error(r, errno); - break; - } - } - - for (;;) { - if (set_get(s, INT_TO_PTR(pid)) != INT_TO_PTR(pid)) { - - /* If we haven't killed this process - * yet, kill it */ - - if (kill(pid, sig) < 0 && errno != ESRCH) { - r = -errno; - break; - } - - killed = true; - done = false; - - if ((r = set_put(s, INT_TO_PTR(pid))) < 0) - break; - } - - if ((r = cgroup_get_task_next(&iterator, &pid)) != 0) { - - if (r == ECGEOF) - r = 0; - else - r = translate_error(r, errno); - - break; - } - } - - kill_done: - assert_se(cgroup_get_task_end(&iterator) == 0); - - /* To avoid racing against processes which fork - * quicker than we can kill them we repeat this until - * no new pids need to be killed. */ - - } while (!done && r >= 0); - - set_free(s); - - if (r < 0) - return r; - - return killed ? 0 : -ESRCH; -} - -int cgroup_bonding_kill_list(CGroupBonding *first, int sig) { - CGroupBonding *b; - int r = -EAGAIN; - - LIST_FOREACH(by_unit, b, first) { - if ((r = cgroup_bonding_kill(b, sig)) < 0) { - if (r == -EAGAIN || -ESRCH) - continue; - - return r; - } - - return 0; - } - - return r; -} - -/* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we - * cannot know */ -int cgroup_bonding_is_empty(CGroupBonding *b) { - void *iterator; - pid_t pid; - int r; - - assert(b); - - r = cgroup_get_task_begin(b->path, b->controller, &iterator, &pid); - - if (r == 0 || r == ECGEOF) - cgroup_get_task_end(&iterator); - - /* Hmm, no PID in this group? Then it is definitely empty */ - if (r == ECGEOF) - return 1; - - /* Some error? Let's return it */ - if (r != 0) - return translate_error(r, errno); - - /* It's not empty, and we are the only user, then it is - * definitely not empty */ - if (b->only_us) - return 0; - - /* There are PIDs in the group but we aren't the only users, - * hence we cannot say */ - return -EAGAIN; -} - -int cgroup_bonding_is_empty_list(CGroupBonding *first) { - CGroupBonding *b; - - LIST_FOREACH(by_unit, b, first) { - int r; - - if ((r = cgroup_bonding_is_empty(b)) < 0) { - /* If this returned -EAGAIN, then we don't know if the - * group is empty, so let's see if another group can - * tell us */ - - if (r != -EAGAIN) - return r; - } else - return r; - } - - return -EAGAIN; -} - -static int install_release_agent(Manager *m, const char *mount_point) { - char *p, *c, *sc; - int r; - - assert(m); - assert(mount_point); - - if (asprintf(&p, "%s/release_agent", mount_point) < 0) - return -ENOMEM; - - if ((r = read_one_line_file(p, &c)) < 0) { - free(p); - return r; - } - - sc = strstrip(c); - - if (sc[0] == 0) { - if ((r = write_one_line_file(p, CGROUP_AGENT_PATH "\n" )) < 0) { - free(p); - free(c); - return r; - } - } else if (!streq(sc, CGROUP_AGENT_PATH)) { - free(p); - free(c); - return -EEXIST; - } - - free(c); - free(p); - - if (asprintf(&p, "%s/notify_on_release", mount_point) < 0) - return -ENOMEM; - - if ((r = read_one_line_file(p, &c)) < 0) { - free(p); - return r; - } - - sc = strstrip(c); - - if (streq(sc, "0")) { - if ((r = write_one_line_file(p, "1\n")) < 0) { - free(p); - free(c); - return r; - } - } else if (!streq(sc, "1")) { - free(p); - free(c); - return -EIO; - } - - free(p); - free(c); - - return 0; -} - -static int create_hierarchy_cgroup(Manager *m) { - struct cgroup *cg; - int r; - - assert(m); - - if (!(cg = cgroup_new_cgroup(m->cgroup_hierarchy))) - return -ENOMEM; - - if (!(cgroup_add_controller(cg, m->cgroup_controller))) { - r = -ENOMEM; - goto finish; - } - - if ((r = cgroup_create_cgroup(cg, true)) != 0) { - log_error("Failed to create cgroup hierarchy group: %s", cgroup_strerror(r)); - r = translate_error(r, errno); - goto finish; - } - - if ((r = cgroup_attach_task(cg)) != 0) { - log_error("Failed to add ourselves to hierarchy group: %s", cgroup_strerror(r)); - r = translate_error(r, errno); - goto finish; - } - - r = 0; - -finish: - cgroup_free(&cg); - return r; -} - -int manager_setup_cgroup(Manager *m) { - char *mp, *cp; - int r; - pid_t pid; - char suffix[32]; - - assert(m); - - if ((r = cgroup_init()) != 0) { - log_error("Failed to initialize libcg: %s", cgroup_strerror(r)); - return translate_error(r, errno); - } - - free(m->cgroup_controller); - if (!(m->cgroup_controller = strdup("debug"))) - return -ENOMEM; - - if ((r = cgroup_get_subsys_mount_point(m->cgroup_controller, &mp))) - return translate_error(r, errno); - - pid = getpid(); - - if ((r = cgroup_get_current_controller_path(pid, m->cgroup_controller, &cp))) { - free(mp); - return translate_error(r, errno); - } - - snprintf(suffix, sizeof(suffix), "/systemd-%u", (unsigned) pid); - char_array_0(suffix); - - free(m->cgroup_hierarchy); - - if (endswith(cp, suffix)) - /* We probably got reexecuted and can continue to use our root cgroup */ - m->cgroup_hierarchy = cp; - else { - /* We need a new root cgroup */ - - m->cgroup_hierarchy = NULL; - r = asprintf(&m->cgroup_hierarchy, "%s%s", streq(cp, "/") ? "" : cp, suffix); - free(cp); - - if (r < 0) { - free(mp); - return -ENOMEM; - } - } - - log_debug("Using cgroup controller <%s>, hierarchy mounted at <%s>, using root group <%s>.", - m->cgroup_controller, - mp, - m->cgroup_hierarchy); - - if ((r = install_release_agent(m, mp)) < 0) - log_warning("Failed to install release agent, ignoring: %s", strerror(-r)); - else - log_debug("Installed release agent, or already installed."); - - free(mp); - - if ((r = create_hierarchy_cgroup(m)) < 0) - log_error("Failed to create root cgroup hierarchy: %s", strerror(-r)); - else - log_debug("Created root group."); - - return r; -} - -int manager_shutdown_cgroup(Manager *m, bool delete) { - struct cgroup *cg; - int r; - - assert(m); - - if (!m->cgroup_hierarchy) - return 0; - - if (!(cg = cgroup_new_cgroup(m->cgroup_hierarchy))) - return -ENOMEM; - - if (!(cgroup_add_controller(cg, m->cgroup_controller))) { - r = -ENOMEM; - goto finish; - } - - /* Often enough we won't be able to delete the cgroup we - * ourselves are in, hence ignore all errors here */ - if (delete) - cgroup_delete_cgroup_ext(cg, CGFLAG_DELETE_IGNORE_MIGRATION|CGFLAG_DELETE_RECURSIVE); - r = 0; - -finish: - cgroup_free(&cg); - return r; - -} - -int cgroup_notify_empty(Manager *m, const char *group) { - CGroupBonding *l, *b; - - assert(m); - assert(group); - - if (!(l = hashmap_get(m->cgroup_bondings, group))) - return 0; - - LIST_FOREACH(by_path, b, l) { - int t; - - if (!b->unit) - continue; - - if ((t = cgroup_bonding_is_empty_list(b)) < 0) { - - /* If we don't know, we don't know */ - if (t != -EAGAIN) - log_warning("Failed to check whether cgroup is empty: %s", strerror(errno)); - - continue; - } - - if (t > 0) - if (UNIT_VTABLE(b->unit)->cgroup_notify_empty) - UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit); - } - - return 0; -} - -CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) { - CGroupBonding *b; - - assert(controller); - - LIST_FOREACH(by_unit, b, first) - if (streq(b->controller, controller)) - return b; - - return NULL; -} - -char *cgroup_bonding_to_string(CGroupBonding *b) { - char *r; - - assert(b); - - if (asprintf(&r, "%s:%s", b->controller, b->path) < 0) - return NULL; - - return r; -} |