cgroup.c revision 0cd385d31814c8c1bc0c81d11ef321036b8b0921
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering/***
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering This file is part of systemd.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Copyright 2013 Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering systemd is free software; you can redistribute it and/or modify it
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering under the terms of the GNU Lesser General Public License as published by
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering (at your option) any later version.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering systemd is distributed in the hope that it will be useful, but
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Lesser General Public License for more details.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering You should have received a copy of the GNU Lesser General Public License
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering***/
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include <fcntl.h>
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include <fnmatch.h>
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "path-util.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "special.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "cgroup-util.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "cgroup.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringvoid cgroup_context_init(CGroupContext *c) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(c);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* Initialize everything to the kernel defaults, assuming the
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * structure is preinitialized to 0 */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c->cpu_shares = (unsigned long) -1;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c->startup_cpu_shares = (unsigned long) -1;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c->memory_limit = (uint64_t) -1;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c->blockio_weight = (unsigned long) -1;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c->startup_blockio_weight = (unsigned long) -1;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c->cpu_quota_per_sec_usec = USEC_INFINITY;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringvoid cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(c);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(a);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering LIST_REMOVE(device_allow, c->device_allow, a);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering free(a->path);
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering free(a);
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering}
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringvoid cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(c);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(w);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering LIST_REMOVE(device_weights, c->blockio_device_weights, w);
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering free(w->path);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering free(w);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringvoid cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(c);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(b);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering LIST_REMOVE(device_bandwidths, c->blockio_device_bandwidths, b);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering free(b->path);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering free(b);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringvoid cgroup_context_done(CGroupContext *c) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(c);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering while (c->blockio_device_weights)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering while (c->blockio_device_bandwidths)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering cgroup_context_free_blockio_device_bandwidth(c, c->blockio_device_bandwidths);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering while (c->device_allow)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering cgroup_context_free_device_allow(c, c->device_allow);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringvoid cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering CGroupBlockIODeviceBandwidth *b;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering CGroupBlockIODeviceWeight *w;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering CGroupDeviceAllow *a;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering char u[FORMAT_TIMESPAN_MAX];
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(c);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(f);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix = strempty(prefix);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering fprintf(f,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%sCPUAccounting=%s\n"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%sBlockIOAccounting=%s\n"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%sMemoryAccounting=%s\n"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%sCPUShares=%lu\n"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%sStartupCPUShares=%lu\n"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%sCPUQuotaPerSecSec=%s\n"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%sBlockIOWeight=%lu\n"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%sStartupBlockIOWeight=%lu\n"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%sMemoryLimit=%" PRIu64 "\n"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%sDevicePolicy=%s\n"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%sDelegate=%s\n",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix, yes_no(c->cpu_accounting),
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix, yes_no(c->blockio_accounting),
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix, yes_no(c->memory_accounting),
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix, c->cpu_shares,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix, c->startup_cpu_shares,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix, format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1),
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix, c->blockio_weight,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix, c->startup_blockio_weight,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix, c->memory_limit,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix, cgroup_device_policy_to_string(c->device_policy),
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix, yes_no(c->delegate));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering LIST_FOREACH(device_allow, a, c->device_allow)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering fprintf(f,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%sDeviceAllow=%s %s%s%s\n",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering a->path,
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering LIST_FOREACH(device_weights, w, c->blockio_device_weights)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering fprintf(f,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%sBlockIODeviceWeight=%s %lu",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering w->path,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering w->weight);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering char buf[FORMAT_BYTES_MAX];
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering fprintf(f,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%s%s=%s %s\n",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering b->read ? "BlockIOReadBandwidth" : "BlockIOWriteBandwidth",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering b->path,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering format_bytes(buf, sizeof(buf), b->bandwidth));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic int lookup_blkio_device(const char *p, dev_t *dev) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering struct stat st;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(p);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(dev);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = stat(p, &st);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return log_warning_errno(errno, "Couldn't stat device %s: %m", p);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (S_ISBLK(st.st_mode))
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering *dev = st.st_rdev;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else if (major(st.st_dev) != 0) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* If this is not a device node then find the block
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * device this file is stored on */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering *dev = st.st_dev;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* If this is a partition, try to get the originating
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * block device */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering block_get_whole_disk(*dev, dev);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering } else {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_warning("%s is not a block device and file system block device cannot be determined or is not local.", p);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -ENODEV;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic int whitelist_device(const char *path, const char *node, const char *acc) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering char buf[2+DECIMAL_STR_MAX(dev_t)*2+2+4];
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering struct stat st;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(path);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(acc);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (stat(node, &st) < 0) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_warning("Couldn't stat device %s", node);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -errno;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_warning("%s is not a device.", node);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -ENODEV;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sprintf(buf,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%c %u:%u %s",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering S_ISCHR(st.st_mode) ? 'c' : 'b',
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering major(st.st_rdev), minor(st.st_rdev),
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering acc);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = cg_set_attribute("devices", path, "devices.allow", buf);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_full(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, "Failed to set devices.allow on %s: %s", path, strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic int whitelist_major(const char *path, const char *name, char type, const char *acc) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering _cleanup_fclose_ FILE *f = NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering char line[LINE_MAX];
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering bool good = false;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(path);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(acc);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(type == 'b' || type == 'c');
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering f = fopen("/proc/devices", "re");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!f)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return log_warning_errno(errno, "Cannot open /proc/devices to resolve %s (%c): %m", name, type);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering FOREACH_LINE(line, f, goto fail) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering char buf[2+DECIMAL_STR_MAX(unsigned)+3+4], *p, *w;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering unsigned maj;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering truncate_nl(line);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (type == 'c' && streq(line, "Character devices:")) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering good = true;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering continue;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (type == 'b' && streq(line, "Block devices:")) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering good = true;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering continue;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (isempty(line)) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering good = false;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering continue;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!good)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering continue;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering p = strstrip(line);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering w = strpbrk(p, WHITESPACE);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!w)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering continue;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering *w = 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = safe_atou(p, &maj);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering continue;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (maj <= 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering continue;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering w++;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering w += strspn(w, WHITESPACE);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (fnmatch(name, w, 0) != 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering continue;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sprintf(buf,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%c %u:* %s",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering type,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering maj,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering acc);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = cg_set_attribute("devices", path, "devices.allow", buf);
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek if (r < 0)
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek log_full(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, "Failed to set devices.allow on %s: %s", path, strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringfail:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_warning_errno(errno, "Failed to read /proc/devices: %m");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -errno;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringvoid cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const char *path, ManagerState state) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering bool is_root;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(c);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(path);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (mask == 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* Some cgroup attributes are not support on the root cgroup,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * hence silently ignore */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering is_root = isempty(path) || path_equal(path, "/");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if ((mask & CGROUP_CPU) && !is_root) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering char buf[MAX(DECIMAL_STR_MAX(unsigned long), DECIMAL_STR_MAX(usec_t)) + 1];
7850b3b83791ba0e2377ba40383c5abc258b839dKay Sievers
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sprintf(buf, "%lu\n",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_cpu_shares != (unsigned long) -1 ? c->startup_cpu_shares :
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c->cpu_shares != (unsigned long) -1 ? c->cpu_shares : 1024);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = cg_set_attribute("cpu", path, "cpu.shares", buf);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_full(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, "Failed to set cpu.shares on %s: %s", path, strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sprintf(buf, USEC_FMT "\n", CGROUP_CPU_QUOTA_PERIOD_USEC);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = cg_set_attribute("cpu", path, "cpu.cfs_period_us", buf);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_full(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, "Failed to set cpu.cfs_period_us on %s: %s", path, strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (c->cpu_quota_per_sec_usec != USEC_INFINITY) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sprintf(buf, USEC_FMT "\n", c->cpu_quota_per_sec_usec * CGROUP_CPU_QUOTA_PERIOD_USEC / USEC_PER_SEC);
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek r = cg_set_attribute("cpu", path, "cpu.cfs_quota_us", buf);
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek } else
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = cg_set_attribute("cpu", path, "cpu.cfs_quota_us", "-1");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_full(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, "Failed to set cpu.cfs_quota_us on %s: %s", path, strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (mask & CGROUP_BLKIO) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering char buf[MAX3(DECIMAL_STR_MAX(unsigned long)+1,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(unsigned long)*1,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)];
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering CGroupBlockIODeviceWeight *w;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering CGroupBlockIODeviceBandwidth *b;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!is_root) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sprintf(buf, "%lu\n", IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_blockio_weight != (unsigned long) -1 ? c->startup_blockio_weight :
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c->blockio_weight != (unsigned long) -1 ? c->blockio_weight : 1000);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = cg_set_attribute("blkio", path, "blkio.weight", buf);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_full(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, "Failed to set blkio.weight on %s: %s", path, strerror(-r));
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek /* FIXME: no way to reset this list */
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek dev_t dev;
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = lookup_blkio_device(w->path, &dev);
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering continue;
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek sprintf(buf, "%u:%u %lu", major(dev), minor(dev), w->weight);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = cg_set_attribute("blkio", path, "blkio.weight_device", buf);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_full(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, "Failed to set blkio.weight_device on %s: %s", path, strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering /* FIXME: no way to reset this list */
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering const char *a;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering dev_t dev;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek r = lookup_blkio_device(b->path, &dev);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering continue;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering a = b->read ? "blkio.throttle.read_bps_device" : "blkio.throttle.write_bps_device";
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->bandwidth);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = cg_set_attribute("blkio", path, a, buf);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_full(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, "Failed to set %s on %s: %s", a, path, strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (mask & CGROUP_MEMORY) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (c->memory_limit != (uint64_t) -1) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering char buf[DECIMAL_STR_MAX(uint64_t) + 1];
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sprintf(buf, "%" PRIu64 "\n", c->memory_limit);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf);
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek } else
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = cg_set_attribute("memory", path, "memory.limit_in_bytes", "-1");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_full(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, "Failed to set memory.limit_in_bytes on %s: %s", path, strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek if ((mask & CGROUP_DEVICE) && !is_root) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering CGroupDeviceAllow *a;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (c->device_allow || c->device_policy != CGROUP_AUTO)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = cg_set_attribute("devices", path, "devices.deny", "a");
943aad8ca57a6b5c49c4ea60f9e8c13bf9b20e6cZbigniew Jędrzejewski-Szmek else
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek r = cg_set_attribute("devices", path, "devices.allow", "a");
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_full(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, "Failed to reset devices.list on %s: %s", path, strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (c->device_policy == CGROUP_CLOSED ||
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering (c->device_policy == CGROUP_AUTO && c->device_allow)) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering static const char auto_devices[] =
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "/dev/null\0" "rwm\0"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "/dev/zero\0" "rwm\0"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "/dev/full\0" "rwm\0"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "/dev/random\0" "rwm\0"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "/dev/urandom\0" "rwm\0"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "/dev/tty\0" "rwm\0"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "/dev/pts/ptmx\0" "rw\0"; /* /dev/pts/ptmx may not be duplicated, but accessed */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering const char *x, *y;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering NULSTR_FOREACH_PAIR(x, y, auto_devices)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering whitelist_device(path, x, y);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering whitelist_major(path, "pts", 'c', "rw");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering whitelist_major(path, "kdbus", 'c', "rw");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering whitelist_major(path, "kdbus/*", 'c', "rw");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering LIST_FOREACH(device_allow, a, c->device_allow) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering char acc[4];
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering unsigned k = 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
4ec24515daa780118709e04cd78dae93f25a8428Zbigniew Jędrzejewski-Szmek if (a->r)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering acc[k++] = 'r';
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (a->w)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering acc[k++] = 'w';
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (a->m)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering acc[k++] = 'm';
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (k == 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering continue;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering acc[k++] = 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (startswith(a->path, "/dev/"))
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering whitelist_device(path, a->path, acc);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else if (startswith(a->path, "block-"))
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering whitelist_major(path, a->path + 6, 'b', acc);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else if (startswith(a->path, "char-"))
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering whitelist_major(path, a->path + 5, 'c', acc);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_debug("Ignoring device %s while writing cgroup attribute.", a->path);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering}
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart PoetteringCGroupControllerMask cgroup_context_get_mask(CGroupContext *c) {
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering CGroupControllerMask mask = 0;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* Figure out which controllers we need */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (c->cpu_accounting ||
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c->cpu_shares != (unsigned long) -1 ||
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c->startup_cpu_shares != (unsigned long) -1 ||
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c->cpu_quota_per_sec_usec != USEC_INFINITY)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering mask |= CGROUP_CPUACCT | CGROUP_CPU;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (c->blockio_accounting ||
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c->blockio_weight != (unsigned long) -1 ||
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c->startup_blockio_weight != (unsigned long) -1 ||
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c->blockio_device_weights ||
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c->blockio_device_bandwidths)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering mask |= CGROUP_BLKIO;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (c->memory_accounting ||
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c->memory_limit != (uint64_t) -1)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering mask |= CGROUP_MEMORY;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (c->device_allow ||
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c->device_policy != CGROUP_AUTO)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering mask |= CGROUP_DEVICE;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return mask;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart PoetteringCGroupControllerMask unit_get_cgroup_mask(Unit *u) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering CGroupContext *c;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering c = unit_get_cgroup_context(u);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!c)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* If delegation is turned on, then turn on all cgroups,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * unless the process we fork into it is known to drop
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * privileges anyway, and shouldn't get access to the
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * controllers anyway. */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (c->delegate) {
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering ExecContext *e;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering e = unit_get_exec_context(u);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!e || exec_context_maintains_privileges(e))
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return _CGROUP_CONTROLLER_MASK_ALL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering return cgroup_context_get_mask(c);
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering}
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart PoetteringCGroupControllerMask unit_get_members_mask(Unit *u) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(u);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (u->cgroup_members_mask_valid)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return u->cgroup_members_mask;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering u->cgroup_members_mask = 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (u->type == UNIT_SLICE) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Unit *member;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Iterator i;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering SET_FOREACH(member, u->dependencies[UNIT_BEFORE], i) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (member == u)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering continue;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (UNIT_DEREF(member->slice) != u)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering continue;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering u->cgroup_members_mask |=
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering unit_get_cgroup_mask(member) |
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering unit_get_members_mask(member);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering u->cgroup_members_mask_valid = true;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return u->cgroup_members_mask;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart PoetteringCGroupControllerMask unit_get_siblings_mask(Unit *u) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(u);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (UNIT_ISSET(u->slice))
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return unit_get_members_mask(UNIT_DEREF(u->slice));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return unit_get_cgroup_mask(u) | unit_get_members_mask(u);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart PoetteringCGroupControllerMask unit_get_target_mask(Unit *u) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering CGroupControllerMask mask;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering mask = unit_get_cgroup_mask(u) | unit_get_members_mask(u) | unit_get_siblings_mask(u);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering mask &= u->manager->cgroup_supported;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return mask;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering/* Recurse from a unit up through its containing slices, propagating
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * mask bits upward. A unit is also member of itself. */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringvoid unit_update_cgroup_members_masks(Unit *u) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering CGroupControllerMask m;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering bool more;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(u);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* Calculate subtree mask */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering m = unit_get_cgroup_mask(u) | unit_get_members_mask(u);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* See if anything changed from the previous invocation. If
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * not, we're done. */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (u->cgroup_subtree_mask_valid && m == u->cgroup_subtree_mask)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek more =
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek u->cgroup_subtree_mask_valid &&
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek ((m & ~u->cgroup_subtree_mask) != 0) &&
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek ((~m & u->cgroup_subtree_mask) == 0);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek u->cgroup_subtree_mask = m;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek u->cgroup_subtree_mask_valid = true;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (UNIT_ISSET(u->slice)) {
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek Unit *s = UNIT_DEREF(u->slice);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (more)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek /* There's more set now than before. We
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek * propagate the new mask to the parent's mask
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek * (not caring if it actually was valid or
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * not). */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering s->cgroup_members_mask |= m;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* There's less set now than before (or we
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * don't know), we need to recalculate
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * everything, so let's invalidate the
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * parent's members mask */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering s->cgroup_members_mask_valid = false;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* And now make sure that this change also hits our
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * grandparents */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering unit_update_cgroup_members_masks(s);
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic const char *migrate_callback(CGroupControllerMask mask, void *userdata) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Unit *u = userdata;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(mask != 0);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(u);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering while (u) {
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (u->cgroup_path &&
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering u->cgroup_realized &&
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering (u->cgroup_realized_mask & mask) == mask)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return u->cgroup_path;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering u = UNIT_DEREF(u->slice);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmekstatic int unit_create_cgroups(Unit *u, CGroupControllerMask mask) {
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *path = NULL;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek CGroupContext *c;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek int r;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek assert(u);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek c = unit_get_cgroup_context(u);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (!c)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return 0;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek path = unit_default_cgroup_path(u);
2e8fb7026d3c560194cfe9f83935ce0b16263da0Lukas Nykryn if (!path)
464264ac5a35b655065c5d95b8d8ffbbc7ff3bcfLukas Nykryn return log_oom();
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek r = hashmap_put(u->manager->cgroup_unit, path, u);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (r < 0) {
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek log_error(r == -EEXIST ? "cgroup %s exists already: %s" : "hashmap_put failed for %s: %s", path, strerror(-r));
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return r;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek }
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (r > 0) {
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek u->cgroup_path = path;
2e8fb7026d3c560194cfe9f83935ce0b16263da0Lukas Nykryn path = NULL;
464264ac5a35b655065c5d95b8d8ffbbc7ff3bcfLukas Nykryn }
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek /* First, create our own group */
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek r = cg_create_everywhere(u->manager->cgroup_supported, mask, u->cgroup_path);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (r < 0)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return log_error_errno(r, "Failed to create cgroup %s: %m", u->cgroup_path);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek /* Keep track that this is now realized */
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek u->cgroup_realized = true;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek u->cgroup_realized_mask = mask;
if (u->type != UNIT_SLICE && !c->delegate) {
/* Then, possibly move things over, but not if
* subgroups may contain processes, which is the case
* for slice and delegation units. */
r = cg_migrate_everywhere(u->manager->cgroup_supported, u->cgroup_path, u->cgroup_path, migrate_callback, u);
if (r < 0)
log_warning_errno(r, "Failed to migrate cgroup from to %s: %m", u->cgroup_path);
}
return 0;
}
static bool unit_has_mask_realized(Unit *u, CGroupControllerMask mask) {
assert(u);
return u->cgroup_realized && u->cgroup_realized_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, ManagerState state) {
CGroupControllerMask mask;
int r;
assert(u);
if (u->in_cgroup_queue) {
LIST_REMOVE(cgroup_queue, u->manager->cgroup_queue, u);
u->in_cgroup_queue = false;
}
mask = unit_get_target_mask(u);
if (unit_has_mask_realized(u, mask))
return 0;
/* First, realize parents */
if (UNIT_ISSET(u->slice)) {
r = unit_realize_cgroup_now(UNIT_DEREF(u->slice), state);
if (r < 0)
return r;
}
/* And then do the real work */
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, state);
return 0;
}
static void unit_add_to_cgroup_queue(Unit *u) {
if (u->in_cgroup_queue)
return;
LIST_PREPEND(cgroup_queue, u->manager->cgroup_queue, u);
u->in_cgroup_queue = true;
}
unsigned manager_dispatch_cgroup_queue(Manager *m) {
ManagerState state;
unsigned n = 0;
Unit *i;
int r;
state = manager_state(m);
while ((i = m->cgroup_queue)) {
assert(i->in_cgroup_queue);
r = unit_realize_cgroup_now(i, state);
if (r < 0)
log_warning_errno(r, "Failed to realize cgroups for queued unit %s: %m", i->id);
n++;
}
return n;
}
static void unit_queue_siblings(Unit *u) {
Unit *slice;
/* This adds the siblings of the specified unit and the
* siblings of all parent units to the cgroup queue. (But
* neither the specified unit itself nor the parents.) */
while ((slice = UNIT_DEREF(u->slice))) {
Iterator i;
Unit *m;
SET_FOREACH(m, slice->dependencies[UNIT_BEFORE], i) {
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);
}
u = slice;
}
}
int unit_realize_cgroup(Unit *u) {
CGroupContext *c;
assert(u);
c = unit_get_cgroup_context(u);
if (!c)
return 0;
/* So, here's the deal: when realizing the cgroups for this
* unit, we need to first create all parents, but there's more
* actually: for the weight-based controllers we also need to
* make sure that all our siblings (i.e. units that are in the
* same slice as we are) have cgroups, too. Otherwise, things
* would become very uneven as each of their processes would
* get as much resources as all our group together. This call
* will synchronously create the parent cgroups, but will
* defer work on the siblings to the next event loop
* iteration. */
/* Add all sibling slices to the cgroup queue. */
unit_queue_siblings(u);
/* And realize this one now (and apply the values) */
return unit_realize_cgroup_now(u, manager_state(u->manager));
}
void unit_destroy_cgroup_if_empty(Unit *u) {
int r;
assert(u);
if (!u->cgroup_path)
return;
r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !unit_has_name(u, SPECIAL_ROOT_SLICE));
if (r < 0) {
log_debug_errno(r, "Failed to destroy cgroup %s: %m", u->cgroup_path);
return;
}
hashmap_remove(u->manager->cgroup_unit, u->cgroup_path);
free(u->cgroup_path);
u->cgroup_path = NULL;
u->cgroup_realized = false;
u->cgroup_realized_mask = 0;
}
pid_t unit_search_main_pid(Unit *u) {
_cleanup_fclose_ FILE *f = NULL;
pid_t pid = 0, npid, mypid;
assert(u);
if (!u->cgroup_path)
return 0;
if (cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &f) < 0)
return 0;
mypid = getpid();
while (cg_read_pid(f, &npid) > 0) {
pid_t ppid;
if (npid == pid)
continue;
/* Ignore processes that aren't our kids */
if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
continue;
if (pid != 0) {
/* Dang, there's more than one daemonized PID
in this group, so we don't know what process
is the main process. */
pid = 0;
break;
}
pid = npid;
}
return pid;
}
int manager_setup_cgroup(Manager *m) {
_cleanup_free_ char *path = NULL;
int r;
assert(m);
/* 1. Determine hierarchy */
free(m->cgroup_root);
m->cgroup_root = NULL;
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &m->cgroup_root);
if (r < 0)
return log_error_errno(r, "Cannot determine cgroup we are running in: %m");
/* LEGACY: Already in /system.slice? If so, let's cut this
* off. This is to support live upgrades from older systemd
* versions where PID 1 was moved there. */
if (m->running_as == SYSTEMD_SYSTEM) {
char *e;
e = endswith(m->cgroup_root, "/" SPECIAL_SYSTEM_SLICE);
if (!e)
e = endswith(m->cgroup_root, "/system");
if (e)
*e = 0;
}
/* And make sure to store away the root value without trailing
* slash, even for the root dir, so that we can easily prepend
* it everywhere. */
if (streq(m->cgroup_root, "/"))
m->cgroup_root[0] = 0;
/* 2. Show data */
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, NULL, &path);
if (r < 0)
return log_error_errno(r, "Cannot find cgroup mount point: %m");
log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
if (!m->test_run) {
/* 3. Install agent */
if (m->running_as == SYSTEMD_SYSTEM) {
r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH);
if (r < 0)
log_warning_errno(r, "Failed to install release agent, ignoring: %m");
else if (r > 0)
log_debug("Installed release agent.");
else
log_debug("Release agent already installed.");
}
/* 4. Make sure we are in the root cgroup */
r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, 0);
if (r < 0)
return log_error_errno(r, "Failed to create root cgroup hierarchy: %m");
/* 5. And pin it, so that it cannot be unmounted */
safe_close(m->pin_cgroupfs_fd);
m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
if (m->pin_cgroupfs_fd < 0)
return log_error_errno(errno, "Failed to open pin file: %m");
/* 6. Always enable hierarchial support if it exists... */
cg_set_attribute("memory", "/", "memory.use_hierarchy", "1");
}
/* 7. Figure out which controllers are supported */
m->cgroup_supported = cg_mask_supported();
return 0;
}
void manager_shutdown_cgroup(Manager *m, bool delete) {
assert(m);
/* We can't really delete the group, since we are in it. But
* let's trim it. */
if (delete && m->cgroup_root)
cg_trim(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, false);
m->pin_cgroupfs_fd = safe_close(m->pin_cgroupfs_fd);
free(m->cgroup_root);
m->cgroup_root = NULL;
}
Unit* manager_get_unit_by_cgroup(Manager *m, const char *cgroup) {
char *p;
Unit *u;
assert(m);
assert(cgroup);
u = hashmap_get(m->cgroup_unit, cgroup);
if (u)
return u;
p = strdupa(cgroup);
for (;;) {
char *e;
e = strrchr(p, '/');
if (e == p || !e)
return NULL;
*e = 0;
u = hashmap_get(m->cgroup_unit, p);
if (u)
return u;
}
}
Unit *manager_get_unit_by_pid(Manager *m, pid_t pid) {
_cleanup_free_ char *cgroup = NULL;
int r;
assert(m);
if (pid <= 1)
return NULL;
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup);
if (r < 0)
return NULL;
return manager_get_unit_by_cgroup(m, cgroup);
}
int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
Unit *u;
int r;
assert(m);
assert(cgroup);
u = manager_get_unit_by_cgroup(m, cgroup);
if (u) {
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
if (r > 0) {
if (UNIT_VTABLE(u)->notify_cgroup_empty)
UNIT_VTABLE(u)->notify_cgroup_empty(u);
unit_add_to_gc_queue(u);
}
}
return 0;
}
static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = {
[CGROUP_AUTO] = "auto",
[CGROUP_CLOSED] = "closed",
[CGROUP_STRICT] = "strict",
};
DEFINE_STRING_TABLE_LOOKUP(cgroup_device_policy, CGroupDevicePolicy);