cgroup.c revision 376dd21dc0757e8a6d3f60d6d21bb802a90f1983
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering This file is part of systemd.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering Copyright 2013 Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering systemd is free software; you can redistribute it and/or modify it
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering under the terms of the GNU Lesser General Public License as published by
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering (at your option) any later version.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering systemd is distributed in the hope that it will be useful, but
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering Lesser General Public License for more details.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering You should have received a copy of the GNU Lesser General Public License
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringvoid cgroup_context_init(CGroupContext *c) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering /* Initialize everything to the kernel defaults, assuming the
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * structure is preinitialized to 0 */
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering c->memory_limit = c->memory_soft_limit = (uint64_t) -1;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringvoid cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering LIST_REMOVE(CGroupDeviceAllow, device_allow, c->device_allow, a);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringvoid cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering LIST_REMOVE(CGroupBlockIODeviceWeight, device_weights, c->blockio_device_weights, w);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringvoid cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering LIST_REMOVE(CGroupBlockIODeviceBandwidth, device_bandwidths, c->blockio_device_bandwidths, b);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringvoid cgroup_context_done(CGroupContext *c) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering cgroup_context_free_blockio_device_bandwidth(c, c->blockio_device_bandwidths);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering cgroup_context_free_device_allow(c, c->device_allow);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringvoid cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering "%sCPUAccounting=%s\n"
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering "%sBlockIOAccounting=%s\n"
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering "%sMemoryAccounting=%s\n"
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering "%sCPUShares=%lu\n"
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering "%sBlockIOWeight%lu\n"
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering "%sDevicePolicy=%s\n",
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering prefix, cgroup_device_policy_to_string(c->device_policy));
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering LIST_FOREACH(device_allow, a, c->device_allow)
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering "%sDeviceAllow=%s %s%s%s\n",
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering LIST_FOREACH(device_weights, w, c->blockio_device_weights)
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering "%sBlockIOWeight=%s %lu",
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering "%s%s=%s %s\n",
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering b->read ? "BlockIOReadBandwidth" : "BlockIOWriteBandwidth",
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering format_bytes(buf, sizeof(buf), b->bandwidth));
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic int lookup_blkio_device(const char *p, dev_t *dev) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering log_warning("Couldn't stat device %s: %m", p);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering /* If this is not a device node then find the block
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * device this file is stored on */
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering /* If this is a partition, try to get the originating
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * block device */
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering log_warning("%s is not a block device and file system block device cannot be determined or is not local.", p);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic int whitelist_device(const char *path, const char *node, const char *acc) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering char buf[2+DECIMAL_STR_MAX(dev_t)*2+2+4];
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering log_warning("Couldn't stat device %s", node);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering log_warning("%s is not a device.", node);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering "%c %u:%u %s",
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering r = cg_set_attribute("devices", path, "devices.allow", buf);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering log_warning("Failed to set devices.allow on %s: %s", path, strerror(-r));
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringvoid cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const char *path) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering char buf[DECIMAL_STR_MAX(unsigned long) + 1];
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering r = cg_set_attribute("cpu", path, "cpu.shares", buf);
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering log_warning("Failed to set cpu.shares on %s: %s", path, strerror(-r));
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering char buf[MAX3(DECIMAL_STR_MAX(unsigned long)+1,
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(unsigned long)*1,
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)];
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering sprintf(buf, "%lu\n", c->blockio_weight);
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering r = cg_set_attribute("blkio", path, "blkio.weight", buf);
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering log_warning("Failed to set blkio.weight on %s: %s", path, strerror(-r));
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering /* FIXME: no way to reset this list */
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering sprintf(buf, "%u:%u %lu", major(dev), minor(dev), w->weight);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering r = cg_set_attribute("blkio", path, "blkio.weight_device", buf);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering log_error("Failed to set blkio.weight_device on %s: %s", path, strerror(-r));
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering /* FIXME: no way to reset this list */
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering const char *a;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering a = b->read ? "blkio.throttle.read_bps_device" : "blkio.throttle.write_bps_device";
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->bandwidth);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering r = cg_set_attribute("blkio", path, a, buf);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering log_error("Failed to set %s on %s: %s", a, path, strerror(-r));
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering sprintf(buf, "%" PRIu64 "\n", c->memory_limit);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering log_error("Failed to set memory.limit_in_bytes on %s: %s", path, strerror(-r));
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering sprintf(buf, "%" PRIu64 "\n", c->memory_soft_limit);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering cg_set_attribute("memory", path, "memory.soft_limit_in_bytes", buf);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering log_error("Failed to set memory.limit_in_bytes on %s: %s", path, strerror(-r));
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (c->device_allow || c->device_policy != CGROUP_AUTO)
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering r = cg_set_attribute("devices", path, "devices.deny", "a");
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering r = cg_set_attribute("devices", path, "devices.allow", "a");
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering log_error("Failed to reset devices.list on %s: %s", path, strerror(-r));
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering (c->device_policy == CGROUP_AUTO && c->device_allow)) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering static const char auto_devices[] =
acc[k++] = 0;
if (c->blockio_accounting ||
c->blockio_device_weights ||
if (c->memory_accounting ||
return mask;
CGroupContext *c;
c = unit_get_cgroup_context(u);
return cgroup_context_get_mask(c);
Unit *m;
Iterator i;
assert(u);
return mask;
assert(u);
assert(u);
if (!path)
return -ENOMEM;
u->cgroup_realized = true;
assert(u);
if (u->in_cgroup_queue) {
u->in_cgroup_queue = false;
if (u->cgroup_realized &&
if (u->in_cgroup_queue)
u->in_cgroup_queue = true;
Unit *i;
while ((i = m->cgroup_queue)) {
if (unit_realize_cgroup_now(i) >= 0)
Iterator i;
Unit *m;
u = slice;
CGroupContext *c;
assert(u);
c = unit_get_cgroup_context(u);
r = unit_realize_cgroup_now(u);
assert(u);
if (!u->cgroup_path)
u->cgroup_realized = false;
u->cgroup_mask = 0;
assert(u);
if (!u->cgroup_path)
if (pid != 0) {
pid = 0;
return pid;
assert(m);
/* Already in /system.slice? If so, let's cut this off again */
m->cgroup_root[0] = 0;
log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
if (m->pin_cgroupfs_fd >= 0)
return -errno;
assert(m);
if (m->pin_cgroupfs_fd >= 0) {
Unit *u;
assert(m);
return NULL;
assert(m);
return NULL;
return NULL;
Unit *u;
assert(m);