X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fcgroup.c;h=c2b1b7d38d2d9cf2b4e6faff71c753f49f607a5a;hp=6a6c5049b39df1377b571baa2d9e51e0fe80c8b4;hb=780896a4f1ec7e36c8f72c866ba9693d790f9741;hpb=f3669545238702f8ffee7b743ca4347b785b558a diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 6a6c5049b..c2b1b7d38 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -346,21 +346,8 @@ static CGroupControllerMask unit_get_cgroup_mask(Unit *u) { } static CGroupControllerMask unit_get_members_mask(Unit *u) { - CGroupControllerMask mask = 0; - Unit *m; - Iterator i; - assert(u); - - SET_FOREACH(m, u->dependencies[UNIT_BEFORE], i) { - - if (UNIT_DEREF(m->slice) != u) - continue; - - mask |= unit_get_cgroup_mask(m) | unit_get_members_mask(m); - } - - return mask; + return u->cgroup_members_mask; } static CGroupControllerMask unit_get_siblings_mask(Unit *u) { @@ -375,24 +362,44 @@ static CGroupControllerMask unit_get_siblings_mask(Unit *u) { (CGROUP_CPU|CGROUP_BLKIO|CGROUP_CPUACCT); } +static CGroupControllerMask unit_get_target_mask(Unit *u) { + CGroupControllerMask mask; + + mask = unit_get_cgroup_mask(u) | unit_get_members_mask(u) | unit_get_siblings_mask(u); + mask &= u->manager->cgroup_supported; + + return mask; +} + +/* Recurse from a unit up through its containing slices, propagating + * mask bits upward. A unit is also member of itself. */ +void unit_update_member_masks(Unit *u) { + u->cgroup_members_mask |= unit_get_cgroup_mask(u); + if (UNIT_ISSET(u->slice)) { + Unit *s = UNIT_DEREF(u->slice); + s->cgroup_members_mask |= u->cgroup_members_mask; + unit_update_member_masks(s); + } +} + static int unit_create_cgroups(Unit *u, CGroupControllerMask mask) { - char *path = NULL; + _cleanup_free_ char *path; int r; - bool is_in_hash = false; + bool was_in_hash = false; assert(u); path = unit_default_cgroup_path(u); if (!path) - return -ENOMEM; + return log_oom(); r = hashmap_put(u->manager->cgroup_unit, path, u); if (r == 0) - is_in_hash = true; - - if (r < 0) { - log_error("cgroup %s exists already: %s", path, strerror(-r)); - free(path); + was_in_hash = true; + else if (r < 0) { + log_error(r == -EEXIST ? + "cgroup %s exists already: %s" : "hashmap_put failed for %s: %s", + path, strerror(-r)); return r; } @@ -405,13 +412,15 @@ static int unit_create_cgroups(Unit *u, CGroupControllerMask mask) { if (u->cgroup_path) { r = cg_migrate_everywhere(u->manager->cgroup_supported, u->cgroup_path, path); if (r < 0) - log_error("Failed to migrate cgroup %s: %s", path, strerror(-r)); + log_error("Failed to migrate cgroup from %s to %s: %s", + u->cgroup_path, path, strerror(-r)); } - if (!is_in_hash) { - /* And remember the new data */ + if (!was_in_hash) { + /* Remember the new data */ free(u->cgroup_path); u->cgroup_path = path; + path = NULL; } u->cgroup_realized = true; @@ -420,8 +429,19 @@ static int unit_create_cgroups(Unit *u, CGroupControllerMask mask) { return 0; } +static bool unit_has_mask_realized(Unit *u, CGroupControllerMask mask) { + return u->cgroup_realized && u->cgroup_mask == mask; +} + +/* Check if necessary controllers and attributes for a unit are in place. + * + * If so, do nothing. + * If not, create paths, move processes over, and set attributes. + * + * Returns 0 on success and < 0 on failure. */ static int unit_realize_cgroup_now(Unit *u) { CGroupControllerMask mask; + int r; assert(u); @@ -430,19 +450,28 @@ static int unit_realize_cgroup_now(Unit *u) { u->in_cgroup_queue = false; } - mask = unit_get_cgroup_mask(u) | unit_get_members_mask(u) | unit_get_siblings_mask(u); - mask &= u->manager->cgroup_supported; + mask = unit_get_target_mask(u); - if (u->cgroup_realized && - u->cgroup_mask == mask) + /* TODO: Consider skipping this check. It may be redundant. */ + if (unit_has_mask_realized(u, mask)) return 0; /* First, realize parents */ - if (UNIT_ISSET(u->slice)) - unit_realize_cgroup_now(UNIT_DEREF(u->slice)); + if (UNIT_ISSET(u->slice)) { + r = unit_realize_cgroup_now(UNIT_DEREF(u->slice)); + if (r < 0) + return r; + } /* And then do the real work */ - return unit_create_cgroups(u, mask); + r = unit_create_cgroups(u, mask); + if (r < 0) + return r; + + /* Finally, apply the necessary attributes. */ + cgroup_context_apply(unit_get_cgroup_context(u), mask, u->cgroup_path); + + return 0; } static void unit_add_to_cgroup_queue(Unit *u) { @@ -457,12 +486,14 @@ static void unit_add_to_cgroup_queue(Unit *u) { unsigned manager_dispatch_cgroup_queue(Manager *m) { Unit *i; unsigned n = 0; + int r; while ((i = m->cgroup_queue)) { assert(i->in_cgroup_queue); - if (unit_realize_cgroup_now(i) >= 0) - cgroup_context_apply(unit_get_cgroup_context(i), i->cgroup_mask, i->cgroup_path); + r = unit_realize_cgroup_now(i); + if (r < 0) + log_warning("Failed to realize cgroups for queued unit %s: %s", i->id, strerror(-r)); n++; } @@ -485,9 +516,22 @@ static void unit_queue_siblings(Unit *u) { if (m == u) continue; + /* Skip units that have a dependency on the slice + * but aren't actually in it. */ if (UNIT_DEREF(m->slice) != slice) continue; + /* No point in doing cgroup application for units + * without active processes. */ + if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(m))) + continue; + + /* If the unit doesn't need any new controllers + * and has current ones realized, it doesn't need + * any changes. */ + if (unit_has_mask_realized(m, unit_get_target_mask(m))) + continue; + unit_add_to_cgroup_queue(m); } @@ -519,13 +563,9 @@ int unit_realize_cgroup(Unit *u) { /* Add all sibling slices to the cgroup queue. */ unit_queue_siblings(u); - /* And realize this one now */ + /* And realize this one now (and apply the values) */ r = unit_realize_cgroup_now(u); - /* And apply the values */ - if (r >= 0) - cgroup_context_apply(c, u->cgroup_mask, u->cgroup_path); - return r; }