summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/cgroup-attr.c132
-rw-r--r--src/core/cgroup-attr.h50
-rw-r--r--src/core/cgroup-semantics.c333
-rw-r--r--src/core/cgroup-semantics.h43
-rw-r--r--src/core/cgroup.c831
-rw-r--r--src/core/cgroup.h116
-rw-r--r--src/core/dbus-cgroup.c139
-rw-r--r--src/core/dbus-cgroup.h44
-rw-r--r--src/core/dbus-execute.c32
-rw-r--r--src/core/dbus-execute.h16
-rw-r--r--src/core/dbus-manager.c148
-rw-r--r--src/core/dbus-mount.c16
-rw-r--r--src/core/dbus-service.c6
-rw-r--r--src/core/dbus-slice.c10
-rw-r--r--src/core/dbus-socket.c14
-rw-r--r--src/core/dbus-swap.c14
-rw-r--r--src/core/dbus-unit.c530
-rw-r--r--src/core/dbus-unit.h28
-rw-r--r--src/core/dbus.c5
-rw-r--r--src/core/execute.c70
-rw-r--r--src/core/execute.h17
-rw-r--r--src/core/load-fragment-gperf.gperf.m425
-rw-r--r--src/core/load-fragment.c435
-rw-r--r--src/core/load-fragment.h9
-rw-r--r--src/core/main.c6
-rw-r--r--src/core/manager.c38
-rw-r--r--src/core/manager.h10
-rw-r--r--src/core/mount.c44
-rw-r--r--src/core/mount.h4
-rw-r--r--src/core/service.c61
-rw-r--r--src/core/service.h1
-rw-r--r--src/core/slice.c79
-rw-r--r--src/core/slice.h2
-rw-r--r--src/core/socket.c17
-rw-r--r--src/core/socket.h1
-rw-r--r--src/core/special.h1
-rw-r--r--src/core/swap.c17
-rw-r--r--src/core/swap.h1
-rw-r--r--src/core/unit.c404
-rw-r--r--src/core/unit.h29
40 files changed, 1309 insertions, 2469 deletions
diff --git a/src/core/cgroup-attr.c b/src/core/cgroup-attr.c
deleted file mode 100644
index 7e3e08eabb..0000000000
--- a/src/core/cgroup-attr.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2011 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "cgroup-attr.h"
-#include "cgroup-util.h"
-#include "list.h"
-#include "fileio.h"
-
-int cgroup_attribute_apply(CGroupAttribute *a, CGroupBonding *b) {
- _cleanup_free_ char *path = NULL, *v = NULL;
- int r;
-
- assert(a);
-
- b = cgroup_bonding_find_list(b, a->controller);
- if (!b)
- return 0;
-
- if (a->semantics && a->semantics->map_write) {
- r = a->semantics->map_write(a->semantics, a->value, &v);
- if (r < 0)
- return r;
- }
-
- r = cg_get_path(a->controller, b->path, a->name, &path);
- if (r < 0)
- return r;
-
- r = write_string_file(path, v ? v : a->value);
- if (r < 0)
- log_warning("Failed to write '%s' to %s: %s", v ? v : a->value, path, strerror(-r));
-
- return r;
-}
-
-int cgroup_attribute_apply_list(CGroupAttribute *first, CGroupBonding *b) {
- CGroupAttribute *a;
- int r = 0;
-
- LIST_FOREACH(by_unit, a, first) {
- int k;
-
- k = cgroup_attribute_apply(a, b);
- if (r == 0)
- r = k;
- }
-
- return r;
-}
-
-bool cgroup_attribute_matches(CGroupAttribute *a, const char *controller, const char *name) {
- assert(a);
-
- if (controller) {
- if (streq(a->controller, controller) && (!name || streq(a->name, name)))
- return true;
-
- } else if (!name)
- return true;
- else if (streq(a->name, name)) {
- size_t x, y;
- x = strlen(a->controller);
- y = strlen(name);
-
- if (y > x &&
- memcmp(a->controller, name, x) == 0 &&
- name[x] == '.')
- return true;
- }
-
- return false;
-}
-
-CGroupAttribute *cgroup_attribute_find_list(
- CGroupAttribute *first,
- const char *controller,
- const char *name) {
- CGroupAttribute *a;
-
- assert(name);
-
- LIST_FOREACH(by_unit, a, first)
- if (cgroup_attribute_matches(a, controller, name))
- return a;
-
- return NULL;
-}
-
-void cgroup_attribute_free(CGroupAttribute *a) {
- assert(a);
-
- if (a->unit)
- LIST_REMOVE(CGroupAttribute, by_unit, a->unit->cgroup_attributes, a);
-
- free(a->controller);
- free(a->name);
- free(a->value);
- free(a);
-}
-
-void cgroup_attribute_free_list(CGroupAttribute *first) {
- CGroupAttribute *a, *n;
-
- LIST_FOREACH_SAFE(by_unit, a, n, first)
- cgroup_attribute_free(a);
-}
-
-void cgroup_attribute_free_some(CGroupAttribute *first, const char *controller, const char *name) {
- CGroupAttribute *a, *n;
-
- LIST_FOREACH_SAFE(by_unit, a, n, first)
- if (cgroup_attribute_matches(a, controller, name))
- cgroup_attribute_free(a);
-}
diff --git a/src/core/cgroup-attr.h b/src/core/cgroup-attr.h
deleted file mode 100644
index 3a13b7c92d..0000000000
--- a/src/core/cgroup-attr.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2011 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct CGroupAttribute CGroupAttribute;
-
-#include "unit.h"
-#include "cgroup.h"
-#include "cgroup-semantics.h"
-
-struct CGroupAttribute {
- char *controller;
- char *name;
- char *value;
-
- Unit *unit;
-
- const CGroupSemantics *semantics;
-
- LIST_FIELDS(CGroupAttribute, by_unit);
-};
-
-int cgroup_attribute_apply(CGroupAttribute *a, CGroupBonding *b);
-int cgroup_attribute_apply_list(CGroupAttribute *first, CGroupBonding *b);
-
-bool cgroup_attribute_matches(CGroupAttribute *a, const char *controller, const char *name) _pure_;
-CGroupAttribute *cgroup_attribute_find_list(CGroupAttribute *first, const char *controller, const char *name) _pure_;
-
-void cgroup_attribute_free(CGroupAttribute *a);
-void cgroup_attribute_free_list(CGroupAttribute *first);
-void cgroup_attribute_free_some(CGroupAttribute *first, const char *controller, const char *name);
diff --git a/src/core/cgroup-semantics.c b/src/core/cgroup-semantics.c
deleted file mode 100644
index 7df9d014e9..0000000000
--- a/src/core/cgroup-semantics.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "util.h"
-#include "strv.h"
-#include "path-util.h"
-#include "cgroup-util.h"
-
-#include "cgroup-semantics.h"
-
-static int parse_cpu_shares(const CGroupSemantics *s, const char *value, char **ret) {
- unsigned long ul;
-
- assert(s);
- assert(value);
- assert(ret);
-
- if (safe_atolu(value, &ul) < 0 || ul < 1)
- return -EINVAL;
-
- if (asprintf(ret, "%lu", ul) < 0)
- return -ENOMEM;
-
- return 1;
-}
-
-static int parse_memory_limit(const CGroupSemantics *s, const char *value, char **ret) {
- off_t sz;
-
- assert(s);
- assert(value);
- assert(ret);
-
- if (parse_bytes(value, &sz) < 0 || sz <= 0)
- return -EINVAL;
-
- if (asprintf(ret, "%llu", (unsigned long long) sz) < 0)
- return -ENOMEM;
-
- return 1;
-}
-
-static int parse_device(const CGroupSemantics *s, const char *value, char **ret) {
- _cleanup_strv_free_ char **l = NULL;
- char *x;
- unsigned k;
-
- assert(s);
- assert(value);
- assert(ret);
-
- l = strv_split_quoted(value);
- if (!l)
- return -ENOMEM;
-
- k = strv_length(l);
- if (k < 1 || k > 2)
- return -EINVAL;
-
- if (!streq(l[0], "*") && !path_startswith(l[0], "/dev"))
- return -EINVAL;
-
- if (!isempty(l[1]) && !in_charset(l[1], "rwm"))
- return -EINVAL;
-
- x = strdup(value);
- if (!x)
- return -ENOMEM;
-
- *ret = x;
- return 1;
-}
-
-static int parse_blkio_weight(const CGroupSemantics *s, const char *value, char **ret) {
- _cleanup_strv_free_ char **l = NULL;
- unsigned long ul;
-
- assert(s);
- assert(value);
- assert(ret);
-
- l = strv_split_quoted(value);
- if (!l)
- return -ENOMEM;
-
- if (strv_length(l) != 1)
- return 0; /* Returning 0 will cause parse_blkio_weight_device() be tried instead */
-
- if (safe_atolu(l[0], &ul) < 0 || ul < 10 || ul > 1000)
- return -EINVAL;
-
- if (asprintf(ret, "%lu", ul) < 0)
- return -ENOMEM;
-
- return 1;
-}
-
-static int parse_blkio_weight_device(const CGroupSemantics *s, const char *value, char **ret) {
- _cleanup_strv_free_ char **l = NULL;
- unsigned long ul;
-
- assert(s);
- assert(value);
- assert(ret);
-
- l = strv_split_quoted(value);
- if (!l)
- return -ENOMEM;
-
- if (strv_length(l) != 2)
- return -EINVAL;
-
- if (!path_startswith(l[0], "/dev"))
- return -EINVAL;
-
- if (safe_atolu(l[1], &ul) < 0 || ul < 10 || ul > 1000)
- return -EINVAL;
-
- if (asprintf(ret, "%s %lu", l[0], ul) < 0)
- return -ENOMEM;
-
- return 1;
-}
-
-static int parse_blkio_bandwidth(const CGroupSemantics *s, const char *value, char **ret) {
- _cleanup_strv_free_ char **l = NULL;
- off_t bytes;
-
- assert(s);
- assert(value);
- assert(ret);
-
- l = strv_split_quoted(value);
- if (!l)
- return -ENOMEM;
-
- if (strv_length(l) != 2)
- return -EINVAL;
-
- if (!path_startswith(l[0], "/dev")) {
- return -EINVAL;
- }
-
- if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0)
- return -EINVAL;
-
- if (asprintf(ret, "%s %llu", l[0], (unsigned long long) bytes) < 0)
- return -ENOMEM;
-
- return 0;
-}
-
-static int map_device(const CGroupSemantics *s, const char *value, char **ret) {
- _cleanup_strv_free_ char **l = NULL;
- unsigned k;
-
- assert(s);
- assert(value);
- assert(ret);
-
- l = strv_split_quoted(value);
- if (!l)
- return -ENOMEM;
-
- k = strv_length(l);
- if (k < 1 || k > 2)
- return -EINVAL;
-
- if (streq(l[0], "*")) {
-
- if (asprintf(ret, "a *:*%s%s",
- isempty(l[1]) ? "" : " ", strempty(l[1])) < 0)
- return -ENOMEM;
- } else {
- struct stat st;
-
- if (stat(l[0], &st) < 0) {
- log_warning("Couldn't stat device %s", l[0]);
- return -errno;
- }
-
- if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
- log_warning("%s is not a device.", l[0]);
- return -ENODEV;
- }
-
- if (asprintf(ret, "%c %u:%u%s%s",
- S_ISCHR(st.st_mode) ? 'c' : 'b',
- major(st.st_rdev), minor(st.st_rdev),
- isempty(l[1]) ? "" : " ", strempty(l[1])) < 0)
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static int map_blkio(const CGroupSemantics *s, const char *value, char **ret) {
- _cleanup_strv_free_ char **l = NULL;
- struct stat st;
- dev_t d;
-
- assert(s);
- assert(value);
- assert(ret);
-
- l = strv_split_quoted(value);
- if (!l)
- return log_oom();
-
- if (strv_length(l) != 2)
- return -EINVAL;
-
- if (stat(l[0], &st) < 0) {
- log_warning("Couldn't stat device %s", l[0]);
- return -errno;
- }
-
- if (S_ISBLK(st.st_mode))
- d = st.st_rdev;
- else if (major(st.st_dev) != 0) {
- /* If this is not a device node then find the block
- * device this file is stored on */
- d = st.st_dev;
-
- /* If this is a partition, try to get the originating
- * block device */
- block_get_whole_disk(d, &d);
- } else {
- log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
- return -ENODEV;
- }
-
- if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0)
- return -ENOMEM;
-
- return 0;
-}
-
-static const CGroupSemantics semantics[] = {
- { "cpu", "cpu.shares", "CPUShares", false, parse_cpu_shares, NULL, NULL },
- { "memory", "memory.soft_limit_in_bytes", "MemorySoftLimit", false, parse_memory_limit, NULL, NULL },
- { "memory", "memory.limit_in_bytes", "MemoryLimit", false, parse_memory_limit, NULL, NULL },
- { "devices", "devices.allow", "DeviceAllow", true, parse_device, map_device, NULL },
- { "devices", "devices.deny", "DeviceDeny", true, parse_device, map_device, NULL },
- { "blkio", "blkio.weight", "BlockIOWeight", false, parse_blkio_weight, NULL, NULL },
- { "blkio", "blkio.weight_device", "BlockIOWeight", true, parse_blkio_weight_device, map_blkio, NULL },
- { "blkio", "blkio.read_bps_device", "BlockIOReadBandwidth", true, parse_blkio_bandwidth, map_blkio, NULL },
- { "blkio", "blkio.write_bps_device", "BlockIOWriteBandwidth", true, parse_blkio_bandwidth, map_blkio, NULL }
-};
-
-int cgroup_semantics_find(
- const char *controller,
- const char *name,
- const char *value,
- char **ret,
- const CGroupSemantics **_s) {
-
- _cleanup_free_ char *c = NULL;
- unsigned i;
- int r;
-
- assert(name);
- assert(_s);
- assert(!value == !ret);
-
- if (!controller) {
- r = cg_controller_from_attr(name, &c);
- if (r < 0)
- return r;
-
- controller = c;
- }
-
- for (i = 0; i < ELEMENTSOF(semantics); i++) {
- const CGroupSemantics *s = semantics + i;
- bool matches_name, matches_pretty;
-
- if (controller && s->controller && !streq(s->controller, controller))
- continue;
-
- matches_name = s->name && streq(s->name, name);
- matches_pretty = s->pretty && streq(s->pretty, name);
-
- if (!matches_name && !matches_pretty)
- continue;
-
- if (value) {
- if (matches_pretty && s->map_pretty) {
-
- r = s->map_pretty(s, value, ret);
- if (r < 0)
- return r;
-
- if (r == 0)
- continue;
-
- } else {
- char *x;
-
- x = strdup(value);
- if (!x)
- return -ENOMEM;
-
- *ret = x;
- }
- }
-
- *_s = s;
- return 1;
- }
-
- *ret = NULL;
- *_s = NULL;
- return 0;
-}
diff --git a/src/core/cgroup-semantics.h b/src/core/cgroup-semantics.h
deleted file mode 100644
index 4f848f4bb7..0000000000
--- a/src/core/cgroup-semantics.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2011 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct CGroupSemantics CGroupSemantics;
-
-struct CGroupSemantics {
- const char *controller;
- const char *name;
- const char *pretty;
-
- bool multiple;
-
- /* This call is used for parsing the pretty value to the actual attribute value */
- int (*map_pretty)(const CGroupSemantics *semantics, const char *value, char **ret);
-
- /* Right before writing this attribute the attribute value is converted to a low-level value */
- int (*map_write)(const CGroupSemantics *semantics, const char *value, char **ret);
-
- /* If this attribute takes a list, this call can be used to reset the list to empty */
- int (*reset)(const CGroupSemantics *semantics, const char *group);
-};
-
-int cgroup_semantics_find(const char *controller, const char *name, const char *value, char **ret, const CGroupSemantics **semantics);
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 5065329739..79467a82ce 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -3,7 +3,7 @@
/***
This file is part of systemd.
- Copyright 2010 Lennart Poettering
+ Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -19,305 +19,554 @@
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 <fcntl.h>
-#include "cgroup.h"
-#include "cgroup-util.h"
-#include "log.h"
-#include "strv.h"
#include "path-util.h"
#include "special.h"
+#include "cgroup-util.h"
+#include "cgroup.h"
-int cgroup_bonding_realize(CGroupBonding *b) {
- int r;
+void cgroup_context_init(CGroupContext *c) {
+ assert(c);
+
+ /* Initialize everything to the kernel defaults, assuming the
+ * structure is preinitialized to 0 */
+
+ c->cpu_shares = 1024;
+ c->memory_limit = c->memory_soft_limit = (uint64_t) -1;
+ c->blockio_weight = 1000;
+}
+void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a) {
+ assert(c);
+ assert(a);
+
+ LIST_REMOVE(CGroupDeviceAllow, device_allow, c->device_allow, a);
+ free(a->path);
+ free(a);
+}
+
+void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w) {
+ assert(c);
+ assert(w);
+
+ LIST_REMOVE(CGroupBlockIODeviceWeight, device_weights, c->blockio_device_weights, w);
+ free(w->path);
+ free(w);
+}
+
+void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b) {
+ assert(c);
assert(b);
- assert(b->path);
- assert(b->controller);
- r = cg_create(b->controller, b->path, NULL);
+ LIST_REMOVE(CGroupBlockIODeviceBandwidth, device_bandwidths, c->blockio_device_bandwidths, b);
+ free(b->path);
+ free(b);
+}
+
+void cgroup_context_done(CGroupContext *c) {
+ assert(c);
+
+ while (c->blockio_device_weights)
+ cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
+
+ while (c->blockio_device_bandwidths)
+ cgroup_context_free_blockio_device_bandwidth(c, c->blockio_device_bandwidths);
+
+ while (c->device_allow)
+ cgroup_context_free_device_allow(c, c->device_allow);
+}
+
+void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
+ CGroupBlockIODeviceBandwidth *b;
+ CGroupBlockIODeviceWeight *w;
+ CGroupDeviceAllow *a;
+
+ assert(c);
+ assert(f);
+
+ prefix = strempty(prefix);
+
+ fprintf(f,
+ "%sCPUAccounting=%s\n"
+ "%sBlockIOAccounting=%s\n"
+ "%sMemoryAccounting=%s\n"
+ "%sCPUShares=%lu\n"
+ "%sBlockIOWeight%lu\n"
+ "%sMemoryLimit=%" PRIu64 "\n"
+ "%sMemorySoftLimit=%" PRIu64 "\n"
+ "%sDevicePolicy=%s\n",
+ prefix, yes_no(c->cpu_accounting),
+ prefix, yes_no(c->blockio_accounting),
+ prefix, yes_no(c->memory_accounting),
+ prefix, c->cpu_shares,
+ prefix, c->blockio_weight,
+ prefix, c->memory_limit,
+ prefix, c->memory_soft_limit,
+ prefix, cgroup_device_policy_to_string(c->device_policy));
+
+ LIST_FOREACH(device_allow, a, c->device_allow)
+ fprintf(f,
+ "%sDeviceAllow=%s %s%s%s\n",
+ prefix,
+ a->path,
+ a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
+
+ LIST_FOREACH(device_weights, w, c->blockio_device_weights)
+ fprintf(f,
+ "%sBlockIOWeight=%s %lu",
+ prefix,
+ w->path,
+ w->weight);
+
+ LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
+ char buf[FORMAT_BYTES_MAX];
+
+ fprintf(f,
+ "%s%s=%s %s\n",
+ prefix,
+ b->read ? "BlockIOReadBandwidth" : "BlockIOWriteBandwidth",
+ b->path,
+ format_bytes(buf, sizeof(buf), b->bandwidth));
+ }
+}
+
+static int lookup_blkio_device(const char *p, dev_t *dev) {
+ struct stat st;
+ int r;
+
+ assert(p);
+ assert(dev);
+
+ r = stat(p, &st);
if (r < 0) {
- log_warning("Failed to create cgroup %s:%s: %s", b->controller, b->path, strerror(-r));
- return r;
+ log_warning("Couldn't stat device %s: %m", p);
+ return -errno;
}
- b->realized = true;
+ if (S_ISBLK(st.st_mode))
+ *dev = st.st_rdev;
+ else if (major(st.st_dev) != 0) {
+ /* If this is not a device node then find the block
+ * device this file is stored on */
+ *dev = st.st_dev;
+
+ /* If this is a partition, try to get the originating
+ * block device */
+ block_get_whole_disk(*dev, dev);
+ } else {
+ log_warning("%s is not a block device and file system block device cannot be determined or is not local.", p);
+ return -ENODEV;
+ }
return 0;
}
-int cgroup_bonding_realize_list(CGroupBonding *first) {
- CGroupBonding *b;
+static int whitelist_device(const char *path, const char *node, const char *acc) {
+ char buf[2+DECIMAL_STR_MAX(dev_t)*2+2+4];
+ struct stat st;
int r;
- LIST_FOREACH(by_unit, b, first)
- if ((r = cgroup_bonding_realize(b)) < 0 && b->essential)
- return r;
+ assert(path);
+ assert(acc);
- return 0;
+ if (stat(node, &st) < 0) {
+ log_warning("Couldn't stat device %s", node);
+ return -errno;
+ }
+
+ if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
+ log_warning("%s is not a device.", node);
+ return -ENODEV;
+ }
+
+ sprintf(buf,
+ "%c %u:%u %s",
+ S_ISCHR(st.st_mode) ? 'c' : 'b',
+ major(st.st_rdev), minor(st.st_rdev),
+ acc);
+
+ r = cg_set_attribute("devices", path, "devices.allow", buf);
+ if (r < 0)
+ log_warning("Failed to set devices.allow on %s: %s", path, strerror(-r));
+
+ return r;
}
-void cgroup_bonding_free(CGroupBonding *b, bool trim) {
- assert(b);
+void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const char *path) {
+ int r;
+
+ assert(c);
+ assert(path);
- if (b->unit) {
- CGroupBonding *f;
+ if (mask == 0)
+ return;
- LIST_REMOVE(CGroupBonding, by_unit, b->unit->cgroup_bondings, b);
+ if (mask & CGROUP_CPU) {
+ char buf[DECIMAL_STR_MAX(unsigned long) + 1];
- if (streq(b->controller, SYSTEMD_CGROUP_CONTROLLER)) {
- assert_se(f = hashmap_get(b->unit->manager->cgroup_bondings, b->path));
- LIST_REMOVE(CGroupBonding, by_path, f, b);
+ sprintf(buf, "%lu\n", c->cpu_shares);
+ r = cg_set_attribute("cpu", path, "cpu.shares", buf);
+ if (r < 0)
+ log_warning("Failed to set cpu.shares on %s: %s", path, strerror(-r));
+ }
+
+ if (mask & CGROUP_BLKIO) {
+ char buf[MAX3(DECIMAL_STR_MAX(unsigned long)+1,
+ DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(unsigned long)*1,
+ DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)];
+ CGroupBlockIODeviceWeight *w;
+ CGroupBlockIODeviceBandwidth *b;
+
+ sprintf(buf, "%lu\n", c->blockio_weight);
+ r = cg_set_attribute("blkio", path, "blkio.weight", buf);
+ if (r < 0)
+ log_warning("Failed to set blkio.weight on %s: %s", path, strerror(-r));
+
+ /* FIXME: no way to reset this list */
+ LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
+ dev_t dev;
+
+ r = lookup_blkio_device(w->path, &dev);
+ if (r < 0)
+ continue;
- if (f)
- hashmap_replace(b->unit->manager->cgroup_bondings, b->path, f);
- else
- hashmap_remove(b->unit->manager->cgroup_bondings, b->path);
+ sprintf(buf, "%u:%u %lu", major(dev), minor(dev), w->weight);
+ r = cg_set_attribute("blkio", path, "blkio.weight_device", buf);
+ if (r < 0)
+ log_error("Failed to set blkio.weight_device on %s: %s", path, strerror(-r));
+ }
+
+ /* FIXME: no way to reset this list */
+ LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
+ const char *a;
+ dev_t dev;
+
+ r = lookup_blkio_device(b->path, &dev);
+ if (r < 0)
+ continue;
+
+ a = b->read ? "blkio.throttle.read_bps_device" : "blkio.throttle.write_bps_device";
+
+ sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->bandwidth);
+ r = cg_set_attribute("blkio", path, a, buf);
+ if (r < 0)
+ log_error("Failed to set %s on %s: %s", a, path, strerror(-r));
}
}
- if (b->realized && b->ours && trim)
- cg_trim(b->controller, b->path, false);
+ if (mask & CGROUP_MEMORY) {
+ char buf[DECIMAL_STR_MAX(uint64_t) + 1];
- free(b->controller);
- free(b->path);
- free(b);
-}
+ sprintf(buf, "%" PRIu64 "\n", c->memory_limit);
+ r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf);
+ if (r < 0)
+ log_error("Failed to set memory.limit_in_bytes on %s: %s", path, strerror(-r));
-void cgroup_bonding_free_list(CGroupBonding *first, bool remove_or_trim) {
- CGroupBonding *b, *n;
+ sprintf(buf, "%" PRIu64 "\n", c->memory_soft_limit);
+ cg_set_attribute("memory", path, "memory.soft_limit_in_bytes", buf);
+ if (r < 0)
+ log_error("Failed to set memory.limit_in_bytes on %s: %s", path, strerror(-r));
+ }
- LIST_FOREACH_SAFE(by_unit, b, n, first)
- cgroup_bonding_free(b, remove_or_trim);
-}
+ if (mask & CGROUP_DEVICE) {
+ CGroupDeviceAllow *a;
-void cgroup_bonding_trim(CGroupBonding *b, bool delete_root) {
- assert(b);
+ if (c->device_allow || c->device_policy != CGROUP_AUTO)
+ r = cg_set_attribute("devices", path, "devices.deny", "a");
+ else
+ r = cg_set_attribute("devices", path, "devices.allow", "a");
+ if (r < 0)
+ log_error("Failed to reset devices.list on %s: %s", path, strerror(-r));
- if (b->realized && b->ours)
- cg_trim(b->controller, b->path, delete_root);
-}
+ if (c->device_policy == CGROUP_CLOSED ||
+ (c->device_policy == CGROUP_AUTO && c->device_allow)) {
+ static const char auto_devices[] =
+ "/dev/null\0" "rw\0"
+ "/dev/zero\0" "rw\0"
+ "/dev/full\0" "rw\0"
+ "/dev/random\0" "rw\0"
+ "/dev/urandom\0" "rw\0";
+
+ const char *x, *y;
+
+ NULSTR_FOREACH_PAIR(x, y, auto_devices)
+ whitelist_device(path, x, y);
+ }
+
+ LIST_FOREACH(device_allow, a, c->device_allow) {
+ char acc[4];
+ unsigned k = 0;
+
+ if (a->r)
+ acc[k++] = 'r';
+ if (a->w)
+ acc[k++] = 'w';
+ if (a->m)
+ acc[k++] = 'm';
-void cgroup_bonding_trim_list(CGroupBonding *first, bool delete_root) {
- CGroupBonding *b;
+ if (k == 0)
+ continue;
- LIST_FOREACH(by_unit, b, first)
- cgroup_bonding_trim(b, delete_root);
+ acc[k++] = 0;
+ whitelist_device(path, a->path, acc);
+ }
+ }
}
-int cgroup_bonding_install(CGroupBonding *b, pid_t pid, const char *cgroup_suffix) {
- _cleanup_free_ char *p = NULL;
- const char *path;
- int r;
+CGroupControllerMask cgroup_context_get_mask(CGroupContext *c) {
+ CGroupControllerMask mask = 0;
- assert(b);
- assert(pid >= 0);
+ /* Figure out which controllers we need */
- if (cgroup_suffix) {
- p = strjoin(b->path, "/", cgroup_suffix, NULL);
- if (!p)
- return -ENOMEM;
+ if (c->cpu_accounting || c->cpu_shares != 1024)
+ mask |= CGROUP_CPUACCT | CGROUP_CPU;
- path = p;
- } else
- path = b->path;
+ if (c->blockio_accounting ||
+ c->blockio_weight != 1000 ||
+ c->blockio_device_weights ||
+ c->blockio_device_bandwidths)
+ mask |= CGROUP_BLKIO;
- r = cg_create_and_attach(b->controller, path, pid);
- if (r < 0)
- return r;
+ if (c->memory_accounting ||
+ c->memory_limit != (uint64_t) -1 ||
+ c->memory_soft_limit != (uint64_t) -1)
+ mask |= CGROUP_MEMORY;
- b->realized = true;
- return 0;
+ if (c->device_allow || c->device_policy != CGROUP_AUTO)
+ mask |= CGROUP_DEVICE;
+
+ return mask;
}
-int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid, const char *cgroup_suffix) {
- CGroupBonding *b;
- int r;
+static CGroupControllerMask unit_get_cgroup_mask(Unit *u) {
+ CGroupContext *c;
- LIST_FOREACH(by_unit, b, first) {
- r = cgroup_bonding_install(b, pid, cgroup_suffix);
- if (r < 0 && b->essential)
- return r;
- }
+ c = unit_get_cgroup_context(u);
+ if (!c)
+ return 0;
- return 0;
+ return cgroup_context_get_mask(c);
}
-int cgroup_bonding_migrate(CGroupBonding *b, CGroupBonding *list) {
- CGroupBonding *q;
- int ret = 0;
+static CGroupControllerMask unit_get_members_mask(Unit *u) {
+ CGroupControllerMask mask = 0;
+ Unit *m;
+ Iterator i;
- LIST_FOREACH(by_unit, q, list) {
- int r;
+ assert(u);
- if (q == b)
- continue;
+ SET_FOREACH(m, u->dependencies[UNIT_BEFORE], i) {
- if (!q->ours)
+ if (UNIT_DEREF(m->slice) != u)
continue;
- r = cg_migrate_recursive(q->controller, q->path, b->controller, b->path, true, false);
- if (r < 0 && ret == 0)
- ret = r;
+ mask |= unit_get_cgroup_mask(m) | unit_get_members_mask(m);
}
- return ret;
+ return mask;
}
-int cgroup_bonding_migrate_to(CGroupBonding *b, const char *target, bool rem) {
- assert(b);
- assert(target);
+static CGroupControllerMask unit_get_siblings_mask(Unit *u) {
+ assert(u);
- return cg_migrate_recursive(b->controller, b->path, b->controller, target, true, rem);
+ if (!UNIT_ISSET(u->slice))
+ return 0;
+
+ /* Sibling propagation is only relevant for weight-based
+ * controllers, so let's mask out everything else */
+ return unit_get_members_mask(UNIT_DEREF(u->slice)) &
+ (CGROUP_CPU|CGROUP_BLKIO|CGROUP_CPUACCT);
}
-int cgroup_bonding_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid) {
- assert(b);
+static int unit_create_cgroups(Unit *u, CGroupControllerMask mask) {
+ char *path = NULL;
+ int r;
- if (!b->realized)
- return -EINVAL;
+ assert(u);
- return cg_set_group_access(b->controller, b->path, mode, uid, gid);
-}
+ path = unit_default_cgroup_path(u);
+ if (!path)
+ return -ENOMEM;
-int cgroup_bonding_set_group_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid) {
- CGroupBonding *b;
- int r;
+ /* First, create our own group */
+ r = cg_create_with_mask(mask, path);
+ if (r < 0)
+ log_error("Failed to create cgroup %s: %s", path, strerror(-r));
- LIST_FOREACH(by_unit, b, first) {
- r = cgroup_bonding_set_group_access(b, mode, uid, gid);
+ /* Then, possibly move things over */
+ if (u->cgroup_path && !streq(path, u->cgroup_path)) {
+ r = cg_migrate_with_mask(mask, u->cgroup_path, path);
if (r < 0)
- return r;
+ log_error("Failed to migrate cgroup %s: %s", path, strerror(-r));
}
+ /* And remember the new data */
+ free(u->cgroup_path);
+ u->cgroup_path = path;
+ u->cgroup_realized = true;
+ u->cgroup_mask = mask;
+
return 0;
}
-int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky) {
- assert(b);
+static void unit_realize_cgroup_now(Unit *u) {
+ CGroupControllerMask mask;
- if (!b->realized)
- return -EINVAL;
+ assert(u);
- return cg_set_task_access(b->controller, b->path, mode, uid, gid, sticky);
-}
+ if (u->in_cgroup_queue) {
+ LIST_REMOVE(Unit, cgroup_queue, u->manager->cgroup_queue, u);
+ u->in_cgroup_queue = false;
+ }
-int cgroup_bonding_set_task_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid, int sticky) {
- CGroupBonding *b;
- int r;
+ mask = unit_get_cgroup_mask(u) | unit_get_members_mask(u) | unit_get_siblings_mask(u);
+ mask &= u->manager->cgroup_supported;
- LIST_FOREACH(by_unit, b, first) {
- r = cgroup_bonding_set_task_access(b, mode, uid, gid, sticky);
- if (r < 0)
- return r;
- }
+ if (u->cgroup_realized &&
+ u->cgroup_mask == mask)
+ return;
- return 0;
+ /* First, realize parents */
+ if (UNIT_ISSET(u->slice))
+ unit_realize_cgroup_now(UNIT_DEREF(u->slice));
+
+ /* And then do the real work */
+ unit_create_cgroups(u, mask);
}
-int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, bool rem, Set *s, const char *cgroup_suffix) {
- char *p = NULL;
- const char *path;
- int r;
+static void unit_add_to_cgroup_queue(Unit *u) {
- assert(b);
- assert(sig >= 0);
+ if (u->in_cgroup_queue)
+ return;
- /* Don't kill cgroups that aren't ours */
- if (!b->ours)
- return 0;
+ LIST_PREPEND(Unit, cgroup_queue, u->manager->cgroup_queue, u);
+ u->in_cgroup_queue = true;
+}
- if (cgroup_suffix) {
- p = strjoin(b->path, "/", cgroup_suffix, NULL);
- if (!p)
- return -ENOMEM;
+unsigned manager_dispatch_cgroup_queue(Manager *m) {
+ Unit *i;
+ unsigned n = 0;
- path = p;
- } else
- path = b->path;
+ while ((i = m->cgroup_queue)) {
+ assert(i->in_cgroup_queue);
- r = cg_kill_recursive(b->controller, path, sig, sigcont, true, rem, s);
- free(p);
+ unit_realize_cgroup_now(i);
+ cgroup_context_apply(unit_get_cgroup_context(i), i->cgroup_mask, i->cgroup_path);
+ n++;
+ }
- return r;
+ return n;
}
-int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, bool rem, Set *s, const char *cgroup_suffix) {
- CGroupBonding *b;
- Set *allocated_set = NULL;
- int ret = -EAGAIN, r;
+static void unit_queue_siblings(Unit *u) {
+ Unit *slice;
- if (!first)
- return 0;
+ /* 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;
- if (!s)
- if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
- return -ENOMEM;
+ SET_FOREACH(m, slice->dependencies[UNIT_BEFORE], i) {
+ if (m == u)
+ continue;
- LIST_FOREACH(by_unit, b, first) {
- r = cgroup_bonding_kill(b, sig, sigcont, rem, s, cgroup_suffix);
- if (r < 0) {
- if (r == -EAGAIN || r == -ESRCH)
+ if (UNIT_DEREF(m->slice) != slice)
continue;
- ret = r;
- goto finish;
+ unit_add_to_cgroup_queue(m);
}
- if (ret < 0 || r > 0)
- ret = r;
+ u = slice;
}
+}
+
+void unit_realize_cgroup(Unit *u) {
+ CGroupContext *c;
+
+ assert(u);
+
+ c = unit_get_cgroup_context(u);
+ if (!c)
+ return;
-finish:
- if (allocated_set)
- set_free(allocated_set);
+ /* 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 cgroup 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. */
- return ret;
+ /* Add all sibling slices to the cgroup queue. */
+ unit_queue_siblings(u);
+
+ /* And realize this one now */
+ unit_realize_cgroup_now(u);
+
+ /* And apply the values */
+ cgroup_context_apply(c, u->cgroup_mask, u->cgroup_path);
}
-/* 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 unit_destroy_cgroup(Unit *u) {
int r;
- assert(b);
+ assert(u);
- if ((r = cg_is_empty_recursive(b->controller, b->path, true)) < 0)
- return r;
+ if (!u->cgroup_path)
+ return;
- /* If it is empty it is empty */
- if (r > 0)
- return 1;
+ r = cg_trim_with_mask(u->cgroup_mask, u->cgroup_path, true);
+ if (r < 0)
+ log_error("Failed to destroy cgroup %s: %s", u->cgroup_path, strerror(-r));
- /* It's not only us using this cgroup, so we just don't know */
- return b->ours ? 0 : -EAGAIN;
+ free(u->cgroup_path);
+ u->cgroup_path = NULL;
+ u->cgroup_realized = false;
+ u->cgroup_mask = 0;
}
-int cgroup_bonding_is_empty_list(CGroupBonding *first) {
- CGroupBonding *b;
+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;
- LIST_FOREACH(by_unit, b, first) {
- int r;
+ /* Ignore processes that aren't our kids */
+ if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
+ continue;
- r = cgroup_bonding_is_empty(b);
- if (r < 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 (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;
+ }
- if (r != -EAGAIN)
- return r;
- } else
- return r;
+ pid = npid;
}
- return -EAGAIN;
+ return pid;
}
int manager_setup_cgroup(Manager *m) {
@@ -394,8 +643,8 @@ int manager_setup_cgroup(Manager *m) {
return -errno;
}
- /* 6. Remove non-existing controllers from the default controllers list */
- cg_shorten_controllers(m->default_controllers);
+ /* 6. Figure out which controllers are supported */
+ m->cgroup_supported = cg_mask_supported();
return 0;
}
@@ -417,201 +666,71 @@ void manager_shutdown_cgroup(Manager *m, bool delete) {
m->cgroup_root = NULL;
}
-int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding) {
- CGroupBonding *b;
+Unit* manager_get_unit_by_cgroup(Manager *m, const char *cgroup) {
char *p;
+ Unit *u;
assert(m);
assert(cgroup);
- assert(bonding);
- b = hashmap_get(m->cgroup_bondings, cgroup);
- if (b) {
- *bonding = b;
- return 1;
- }
+ u = hashmap_get(m->cgroup_unit, cgroup);
+ if (u)
+ return u;
p = strdupa(cgroup);
- if (!p)
- return -ENOMEM;
-
for (;;) {
char *e;
e = strrchr(p, '/');
- if (e == p || !e) {
- *bonding = NULL;
- return 0;
- }
+ if (e == p || !e)
+ return NULL;
*e = 0;
- b = hashmap_get(m->cgroup_bondings, p);
- if (b) {
- *bonding = b;
- return 1;
- }
+ u = hashmap_get(m->cgroup_unit, p);
+ if (u)
+ return u;
}
}
-int cgroup_notify_empty(Manager *m, const char *group) {
- CGroupBonding *l, *b;
+Unit *manager_get_unit_by_pid(Manager *m, pid_t pid) {
+ _cleanup_free_ char *cgroup = NULL;
int r;
assert(m);
- assert(group);
-
- r = cgroup_bonding_get(m, group, &l);
- if (r <= 0)
- return r;
-
- LIST_FOREACH(by_path, b, l) {
- int t;
-
- if (!b->unit)
- continue;
-
- t = cgroup_bonding_is_empty_list(b);
- if (t < 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 it is empty, let's delete it */
- cgroup_bonding_trim_list(b->unit->cgroup_bondings, true);
-
- if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
- UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
- }
- }
-
- return 0;
-}
-
-Unit* cgroup_unit_by_pid(Manager *m, pid_t pid) {
- CGroupBonding *l, *b;
- char *group = NULL;
-
- assert(m);
if (pid <= 1)
return NULL;
- if (cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0)
- return NULL;
-
- l = hashmap_get(m->cgroup_bondings, group);
-
- if (!l) {
- char *slash;
-
- while ((slash = strrchr(group, '/'))) {
- if (slash == group)
- break;
-
- *slash = 0;
-
- if ((l = hashmap_get(m->cgroup_bondings, group)))
- break;
- }
- }
-
- free(group);
-
- LIST_FOREACH(by_path, b, l) {
-
- if (!b->unit)
- continue;
-
- if (b->ours)
- return b->unit;
- }
-
- return NULL;
-}
-
-CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) {
- CGroupBonding *b;
-
- if (!controller)
- controller = SYSTEMD_CGROUP_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)
+ r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup);
+ if (r < 0)
return NULL;
- return r;
+ return manager_get_unit_by_cgroup(m, cgroup);
}
-pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) {
- FILE *f;
- pid_t pid = 0, npid, mypid;
-
- assert(b);
+int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
+ Unit *u;
+ int r;
- if (!b->ours)
- return 0;
+ assert(m);
+ assert(cgroup);
- if (cg_enumerate_processes(b->controller, b->path, &f) < 0)
+ r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, true);
+ if (r == 0)
return 0;
- mypid = getpid();
+ u = manager_get_unit_by_cgroup(m, cgroup);
+ if (u && UNIT_VTABLE(u)->notify_cgroup_empty)
+ UNIT_VTABLE(u)->notify_cgroup_empty(u);
- 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;
- }
-
- fclose(f);
-
- return pid;
+ return 0;
}
-pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *first) {
- CGroupBonding *b;
- pid_t pid;
-
- /* Try to find a main pid from this cgroup, but checking if
- * there's only one PID in the cgroup and returning it. Later
- * on we might want to add additional, smarter heuristics
- * here. */
-
- LIST_FOREACH(by_unit, b, first)
- if ((pid = cgroup_bonding_search_main_pid(b)) != 0)
- return pid;
+static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = {
+ [CGROUP_AUTO] = "auto",
+ [CGROUP_CLOSED] = "closed",
+ [CGROUP_STRICT] = "strict",
+};
- return 0;
-
-}
+DEFINE_STRING_TABLE_LOOKUP(cgroup_device_policy, CGroupDevicePolicy);
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index 6555d89e37..96f1d9f7b6 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -5,7 +5,7 @@
/***
This file is part of systemd.
- Copyright 2010 Lennart Poettering
+ Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -21,74 +21,96 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-typedef struct CGroupBonding CGroupBonding;
+#include "list.h"
-#include "unit.h"
+typedef struct CGroupContext CGroupContext;
+typedef struct CGroupDeviceAllow CGroupDeviceAllow;
+typedef struct CGroupBlockIODeviceWeight CGroupBlockIODeviceWeight;
+typedef struct CGroupBlockIODeviceBandwidth CGroupBlockIODeviceBandwidth;
-/* Binds a cgroup to a name */
-struct CGroupBonding {
- char *controller;
- char *path;
+typedef enum CGroupDevicePolicy {
- Unit *unit;
+ /* When devices listed, will allow those, plus built-in ones,
+ if none are listed will allow everything. */
+ CGROUP_AUTO,
- /* For the Unit::cgroup_bondings list */
- LIST_FIELDS(CGroupBonding, by_unit);
+ /* Everything forbidden, except built-in ones and listed ones. */
+ CGROUP_CLOSED,
- /* For the Manager::cgroup_bondings hashmap */
- LIST_FIELDS(CGroupBonding, by_path);
+ /* Everythings forbidden, except for the listed devices */
+ CGROUP_STRICT,
- /* When shutting down, remove cgroup? Are our own tasks the
- * only ones in this group?*/
- bool ours:1;
+ _CGROUP_DEVICE_POLICY_MAX,
+ _CGROUP_DEVICE_POLICY_INVALID = -1
+} CGroupDevicePolicy;
- /* If we cannot create this group, or add a process to it, is this fatal? */
- bool essential:1;
+struct CGroupDeviceAllow {
+ LIST_FIELDS(CGroupDeviceAllow, device_allow);
+ char *path;
+ bool r:1;
+ bool w:1;
+ bool m:1;
+};
- /* This cgroup is realized */
- bool realized:1;
+struct CGroupBlockIODeviceWeight {
+ LIST_FIELDS(CGroupBlockIODeviceWeight, device_weights);
+ char *path;
+ unsigned long weight;
};
-int cgroup_bonding_realize(CGroupBonding *b);
-int cgroup_bonding_realize_list(CGroupBonding *first);
+struct CGroupBlockIODeviceBandwidth {
+ LIST_FIELDS(CGroupBlockIODeviceBandwidth, device_bandwidths);
+ char *path;
+ uint64_t bandwidth;
+ bool read;
+};
-void cgroup_bonding_free(CGroupBonding *b, bool trim);
-void cgroup_bonding_free_list(CGroupBonding *first, bool trim);
+struct CGroupContext {
+ bool cpu_accounting;
+ bool blockio_accounting;
+ bool memory_accounting;
-int cgroup_bonding_install(CGroupBonding *b, pid_t pid, const char *suffix);
-int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid, const char *suffix);
+ unsigned long cpu_shares;
-int cgroup_bonding_migrate(CGroupBonding *b, CGroupBonding *list);
-int cgroup_bonding_migrate_to(CGroupBonding *b, const char *target, bool rem);
+ unsigned long blockio_weight;
+ LIST_HEAD(CGroupBlockIODeviceWeight, blockio_device_weights);
+ LIST_HEAD(CGroupBlockIODeviceBandwidth, blockio_device_bandwidths);
-int cgroup_bonding_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid);
-int cgroup_bonding_set_group_access_list(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid);
+ uint64_t memory_limit;
+ uint64_t memory_soft_limit;
-int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky);
-int cgroup_bonding_set_task_access_list(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky);
+ CGroupDevicePolicy device_policy;
+ LIST_HEAD(CGroupDeviceAllow, device_allow);
+};
-int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, bool rem, Set *s, const char *suffix);
-int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, bool rem, Set *s, const char *suffix);
+#include "unit.h"
+#include "manager.h"
+#include "cgroup-util.h"
-void cgroup_bonding_trim(CGroupBonding *first, bool delete_root);
-void cgroup_bonding_trim_list(CGroupBonding *first, bool delete_root);
+void cgroup_context_init(CGroupContext *c);
+void cgroup_context_done(CGroupContext *c);
+void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix);
+void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const char *path);
+CGroupControllerMask cgroup_context_get_mask(CGroupContext *c);
-int cgroup_bonding_is_empty(CGroupBonding *b);
-int cgroup_bonding_is_empty_list(CGroupBonding *first);
+void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a);
+void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w);
+void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b);
-CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) _pure_;
+void unit_realize_cgroup(Unit *u);
+void unit_destroy_cgroup(Unit *u);
-char *cgroup_bonding_to_string(CGroupBonding *b);
+int manager_setup_cgroup(Manager *m);
+void manager_shutdown_cgroup(Manager *m, bool delete);
-pid_t cgroup_bonding_search_main_pid(CGroupBonding *b);
-pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *b);
+unsigned manager_dispatch_cgroup_queue(Manager *m);
-#include "manager.h"
+Unit *manager_get_unit_by_cgroup(Manager *m, const char *cgroup);
+Unit* manager_get_unit_by_pid(Manager *m, pid_t pid);
-int manager_setup_cgroup(Manager *m);
-void manager_shutdown_cgroup(Manager *m, bool delete);
+pid_t unit_search_main_pid(Unit *u);
-int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding);
-int cgroup_notify_empty(Manager *m, const char *group);
+int manager_notify_cgroup_empty(Manager *m, const char *group);
-Unit* cgroup_unit_by_pid(Manager *m, pid_t pid);
+const char* cgroup_device_policy_to_string(CGroupDevicePolicy i) _const_;
+CGroupDevicePolicy cgroup_device_policy_from_string(const char *s) _pure_;
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
new file mode 100644
index 0000000000..08ee9c8db4
--- /dev/null
+++ b/src/core/dbus-cgroup.c
@@ -0,0 +1,139 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include "dbus-cgroup.h"
+
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_cgroup_append_device_policy, cgroup_device_policy, CGroupDevicePolicy);
+
+static int bus_cgroup_append_device_weights(DBusMessageIter *i, const char *property, void *data) {
+ DBusMessageIter sub, sub2;
+ CGroupContext *c = data;
+ CGroupBlockIODeviceWeight *w;
+
+ assert(i);
+ assert(property);
+ assert(c);
+
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(st)", &sub))
+ return -ENOMEM;
+
+ LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
+
+ if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &w->path) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &w->weight) ||
+ !dbus_message_iter_close_container(&sub, &sub2))
+ return -ENOMEM;
+ }
+
+ if (!dbus_message_iter_close_container(i, &sub))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int bus_cgroup_append_device_bandwidths(DBusMessageIter *i, const char *property, void *data) {
+ DBusMessageIter sub, sub2;
+ CGroupContext *c = data;
+ CGroupBlockIODeviceBandwidth *b;
+
+ assert(i);
+ assert(property);
+ assert(c);
+
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(st)", &sub))
+ return -ENOMEM;
+
+ LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
+
+ if (streq(property, "BlockIOReadBandwidth") != b->read)
+ continue;
+
+ if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &b->path) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &b->bandwidth) ||
+ !dbus_message_iter_close_container(&sub, &sub2))
+ return -ENOMEM;
+ }
+
+ if (!dbus_message_iter_close_container(i, &sub))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int bus_cgroup_append_device_allow(DBusMessageIter *i, const char *property, void *data) {
+ DBusMessageIter sub, sub2;
+ CGroupContext *c = data;
+ CGroupDeviceAllow *a;
+
+ assert(i);
+ assert(property);
+ assert(c);
+
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(ss)", &sub))
+ return -ENOMEM;
+
+ LIST_FOREACH(device_allow, a, c->device_allow) {
+ const char *rwm;
+ char buf[4];
+ unsigned k = 0;
+
+ if (a->r)
+ buf[k++] = 'r';
+ if (a->w)
+ buf[k++] = 'w';
+ if (a->m)
+ buf[k++] = 'm';
+
+ buf[k] = 0;
+ rwm = buf;
+
+ if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->path) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &rwm) ||
+ !dbus_message_iter_close_container(&sub, &sub2))
+ return -ENOMEM;
+ }
+
+ if (!dbus_message_iter_close_container(i, &sub))
+ return -ENOMEM;
+
+ return 0;
+}
+
+const BusProperty bus_cgroup_context_properties[] = {
+ { "CPUAccounting", bus_property_append_bool, "b", offsetof(CGroupContext, cpu_accounting) },
+ { "CPUShares", bus_property_append_ul, "t", offsetof(CGroupContext, cpu_shares) },
+ { "BlockIOAccounting", bus_property_append_bool, "b", offsetof(CGroupContext, blockio_accounting) },
+ { "BlockIOWeight", bus_property_append_ul, "t", offsetof(CGroupContext, blockio_weight) },
+ { "BlockIODeviceWeight", bus_cgroup_append_device_weights, "a(st)", 0 },
+ { "BlockIOReadBandwidth", bus_cgroup_append_device_bandwidths, "a(st)", 0 },
+ { "BlockIOWriteBandwidth", bus_cgroup_append_device_bandwidths, "a(st)", 0 },
+ { "MemoryAccounting", bus_property_append_bool, "b", offsetof(CGroupContext, memory_accounting) },
+ { "MemoryLimit", bus_property_append_uint64, "t", offsetof(CGroupContext, memory_limit) },
+ { "MemorySoftLimit", bus_property_append_uint64, "t", offsetof(CGroupContext, memory_soft_limit) },
+ { "DevicePolicy", bus_cgroup_append_device_policy, "s", offsetof(CGroupContext, device_policy) },
+ { "DeviceAllow", bus_cgroup_append_device_allow, "a(ss)", 0 },
+ {}
+};
diff --git a/src/core/dbus-cgroup.h b/src/core/dbus-cgroup.h
new file mode 100644
index 0000000000..a0a7a7771e
--- /dev/null
+++ b/src/core/dbus-cgroup.h
@@ -0,0 +1,44 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include "manager.h"
+#include "dbus-common.h"
+#include "cgroup.h"
+
+#define BUS_CGROUP_CONTEXT_INTERFACE \
+ " <property name=\"CPUAccounting\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"CPUShares\" type=\"t\" access=\"read\"/>\n" \
+ " <property name=\"BlockIOAccounting\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"BlockIOWeight\" type=\"t\" access=\"read\"/>\n" \
+ " <property name=\"BlockIODeviceWeight\" type=\"a(st)\" access=\"read\"/>\n" \
+ " <property name=\"BlockIOReadBandwidth=\" type=\"a(st)\" access=\"read\"/>\n" \
+ " <property name=\"BlockIOWriteBandwidth=\" type=\"a(st)\" access=\"read\"/>\n" \
+ " <property name=\"MemoryAccounting\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"MemoryLimit\" type=\"t\" access=\"read\"/>\n" \
+ " <property name=\"MemorySoftLimit\" type=\"t\" access=\"read\"/>\n" \
+ " <property name=\"DevicePolicy\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"DeviceAllow\" type=\"a(ss)\" access=\"read\"/>\n"
+
+extern const BusProperty bus_cgroup_context_properties[];
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 2a8a0e1ac5..73590c82be 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -31,10 +31,10 @@
#include "syscall-list.h"
#include "fileio.h"
-DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput);
-DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput);
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput);
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput);
-int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data) {
+static int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data) {
char **env_files = data, **j;
DBusMessageIter sub, sub2;
@@ -66,7 +66,7 @@ int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void
return 0;
}
-int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data) {
+static int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data) {
ExecContext *c = data;
int32_t n;
@@ -92,7 +92,7 @@ int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property
return 0;
}
-int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data) {
+static int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data) {
ExecContext *c = data;
int32_t n;
@@ -111,7 +111,7 @@ int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data
return 0;
}
-int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data) {
+static int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data) {
ExecContext *c = data;
int32_t n;
@@ -130,7 +130,7 @@ int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *da
return 0;
}
-int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data) {
+static int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data) {
ExecContext *c = data;
int32_t n;
@@ -149,7 +149,7 @@ int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property
return 0;
}
-int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data) {
+static int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data) {
ExecContext *c = data;
int32_t n;
@@ -174,7 +174,7 @@ int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *proper
return 0;
}
-int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data) {
+static int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data) {
ExecContext *c = data;
dbus_bool_t b;
DBusMessageIter sub;
@@ -200,7 +200,7 @@ int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *
return 0;
}
-int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data) {
+static int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data) {
ExecContext *c = data;
uint64_t u;
@@ -219,7 +219,7 @@ int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property
return 0;
}
-int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data) {
+static int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data) {
ExecContext *c = data;
uint64_t normal, inverted;
@@ -236,7 +236,7 @@ int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, v
return bus_property_append_uint64(i, property, &inverted);
}
-int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data) {
+static int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data) {
ExecContext *c = data;
char *t = NULL;
const char *s;
@@ -265,7 +265,7 @@ int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, vo
return 0;
}
-int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data) {
+static int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data) {
ExecContext *c = data;
int r;
uint64_t u;
@@ -347,7 +347,7 @@ int bus_execute_append_command(DBusMessageIter *i, const char *property, void *d
return 0;
}
-int bus_execute_append_syscall_filter(DBusMessageIter *i, const char *property, void *data) {
+static int bus_execute_append_syscall_filter(DBusMessageIter *i, const char *property, void *data) {
ExecContext *c = data;
dbus_bool_t b;
DBusMessageIter sub;
@@ -430,10 +430,8 @@ const BusProperty bus_exec_context_properties[] = {
{ "PrivateNetwork", bus_property_append_bool, "b", offsetof(ExecContext, private_network) },
{ "SameProcessGroup", bus_property_append_bool, "b", offsetof(ExecContext, same_pgrp) },
{ "UtmpIdentifier", bus_property_append_string, "s", offsetof(ExecContext, utmp_id), true },
- { "ControlGroupModify", bus_property_append_bool, "b", offsetof(ExecContext, control_group_modify) },
- { "ControlGroupPersistent", bus_property_append_tristate_false, "b", offsetof(ExecContext, control_group_persistent) },
{ "IgnoreSIGPIPE", bus_property_append_bool, "b", offsetof(ExecContext, ignore_sigpipe) },
{ "NoNewPrivileges", bus_property_append_bool, "b", offsetof(ExecContext, no_new_privileges) },
{ "SystemCallFilter", bus_execute_append_syscall_filter, "au", 0 },
- { NULL, }
+ {}
};
diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h
index 91d70e535f..5a6a559c99 100644
--- a/src/core/dbus-execute.h
+++ b/src/core/dbus-execute.h
@@ -92,8 +92,6 @@
" <property name=\"PrivateNetwork\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"SameProcessGroup\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"UtmpIdentifier\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"ControlGroupModify\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"ControlGroupPersistent\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"IgnoreSIGPIPE\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"NoNewPrivileges\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"SystemCallFilter\" type=\"au\" access=\"read\"/>\n"
@@ -106,18 +104,4 @@ extern const BusProperty bus_exec_context_properties[];
#define BUS_EXEC_COMMAND_PROPERTY(name, command, indirect) \
{ name, bus_execute_append_command, "a(sasbttttuii)", (command), (indirect), NULL }
-int bus_execute_append_output(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_input(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data);
int bus_execute_append_command(DBusMessageIter *u, const char *property, void *data);
-int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_syscall_filter(DBusMessageIter *i, const char *property, void *data);
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index d41b6ae15f..c081ff5d16 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -613,7 +613,6 @@ static const BusProperty bus_manager_properties[] = {
{ "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
{ "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
{ "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
- { "DefaultControllers", bus_property_append_strv, "as", offsetof(Manager, default_controllers), true },
{ "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
{ "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
{ "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
@@ -683,7 +682,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
DBUS_TYPE_INVALID))
return bus_send_error_reply(connection, message, &error, -EINVAL);
- u = cgroup_unit_by_pid(m, (pid_t) pid);
+ u = manager_get_unit_by_pid(m, (pid_t) pid);
if (!u) {
dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
return bus_send_error_reply(connection, message, &error, -ENOENT);
@@ -896,151 +895,6 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
if (!reply)
goto oom;
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitControlGroup")) {
- const char *name;
- Unit *u;
- DBusMessageIter iter;
-
- if (!dbus_message_iter_init(message, &iter))
- goto oom;
-
- r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- u = manager_get_unit(m, name);
- if (!u) {
- dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
- return bus_send_error_reply(connection, message, &error, -ENOENT);
- }
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
-
- r = bus_unit_cgroup_set(u, &iter);
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetUnitControlGroup")) {
- const char *name;
- Unit *u;
- DBusMessageIter iter;
-
- if (!dbus_message_iter_init(message, &iter))
- goto oom;
-
- r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- u = manager_get_unit(m, name);
- if (!u) {
- dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
- return bus_send_error_reply(connection, message, &error, -ENOENT);
- }
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
-
- r = bus_unit_cgroup_unset(u, &iter);
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitControlGroupAttribute")) {
- const char *name;
- Unit *u;
- DBusMessageIter iter;
-
- if (!dbus_message_iter_init(message, &iter))
- goto oom;
-
- r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- u = manager_get_unit(m, name);
- if (!u) {
- dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
- return bus_send_error_reply(connection, message, &error, -ENOENT);
- }
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
-
- r = bus_unit_cgroup_attribute_set(u, &iter);
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetUnitControlGroupAttribute")) {
- const char *name;
- Unit *u;
- DBusMessageIter iter;
-
- if (!dbus_message_iter_init(message, &iter))
- goto oom;
-
- r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- u = manager_get_unit(m, name);
- if (!u) {
- dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
- return bus_send_error_reply(connection, message, &error, -ENOENT);
- }
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
-
- r = bus_unit_cgroup_attribute_unset(u, &iter);
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitControlGroupAttribute")) {
- const char *name;
- Unit *u;
- DBusMessageIter iter;
- _cleanup_strv_free_ char **list = NULL;
-
- if (!dbus_message_iter_init(message, &iter))
- goto oom;
-
- r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- u = manager_get_unit(m, name);
- if (!u) {
- dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
- return bus_send_error_reply(connection, message, &error, -ENOENT);
- }
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
-
- r = bus_unit_cgroup_attribute_get(u, &iter, &list);
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- dbus_message_iter_init_append(reply, &iter);
- if (bus_append_strv_iter(&iter, list) < 0)
- goto oom;
-
} else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
DBusMessageIter iter, sub;
Iterator i;
diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c
index 0fcceb500d..16b7afe8b7 100644
--- a/src/core/dbus-mount.c
+++ b/src/core/dbus-mount.c
@@ -22,11 +22,12 @@
#include <errno.h>
#include "dbus-unit.h"
-#include "dbus-mount.h"
-#include "dbus-kill.h"
#include "dbus-execute.h"
+#include "dbus-kill.h"
+#include "dbus-cgroup.h"
#include "dbus-common.h"
#include "selinux-access.h"
+#include "dbus-mount.h"
#define BUS_MOUNT_INTERFACE \
" <interface name=\"org.freedesktop.systemd1.Mount\">\n" \
@@ -40,7 +41,6 @@
BUS_EXEC_COMMAND_INTERFACE("ExecRemount") \
BUS_EXEC_CONTEXT_INTERFACE \
BUS_KILL_CONTEXT_INTERFACE \
- BUS_UNIT_CGROUP_INTERFACE \
" <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
" <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
" <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \
@@ -156,11 +156,11 @@ DBusHandlerResult bus_mount_message_handler(Unit *u, DBusConnection *c, DBusMess
Mount *m = MOUNT(u);
const BusBoundProperties bps[] = {
- { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
- { "org.freedesktop.systemd1.Mount", bus_mount_properties, m },
- { "org.freedesktop.systemd1.Mount", bus_exec_context_properties, &m->exec_context },
- { "org.freedesktop.systemd1.Mount", bus_kill_context_properties, &m->kill_context },
- { "org.freedesktop.systemd1.Mount", bus_unit_cgroup_properties, u },
+ { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
+ { "org.freedesktop.systemd1.Mount", bus_mount_properties, m },
+ { "org.freedesktop.systemd1.Mount", bus_exec_context_properties, &m->exec_context },
+ { "org.freedesktop.systemd1.Mount", bus_kill_context_properties, &m->kill_context },
+ { "org.freedesktop.systemd1.Mount", bus_cgroup_context_properties, &m->cgroup_context },
{ NULL, }
};
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index 98bcdcb402..bbac1b8167 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -24,9 +24,10 @@
#include "dbus-unit.h"
#include "dbus-execute.h"
#include "dbus-kill.h"
-#include "dbus-service.h"
+#include "dbus-cgroup.h"
#include "dbus-common.h"
#include "selinux-access.h"
+#include "dbus-service.h"
#define BUS_SERVICE_INTERFACE \
" <interface name=\"org.freedesktop.systemd1.Service\">\n" \
@@ -50,7 +51,6 @@
BUS_EXEC_COMMAND_INTERFACE("ExecStopPost") \
BUS_EXEC_CONTEXT_INTERFACE \
BUS_KILL_CONTEXT_INTERFACE \
- BUS_UNIT_CGROUP_INTERFACE \
" <property name=\"PermissionsStartOnly\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"RootDirectoryStartOnly\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"RemainAfterExit\" type=\"b\" access=\"read\"/>\n" \
@@ -152,8 +152,8 @@ DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connectio
{ "org.freedesktop.systemd1.Service", bus_service_properties, s },
{ "org.freedesktop.systemd1.Service", bus_exec_context_properties, &s->exec_context },
{ "org.freedesktop.systemd1.Service", bus_kill_context_properties, &s->kill_context },
+ { "org.freedesktop.systemd1.Service", bus_cgroup_context_properties, &s->cgroup_context },
{ "org.freedesktop.systemd1.Service", bus_exec_main_status_properties, &s->main_exec_status },
- { "org.freedesktop.systemd1.Service", bus_unit_cgroup_properties, u },
{ NULL, }
};
diff --git a/src/core/dbus-slice.c b/src/core/dbus-slice.c
index 8a318faa55..8243305848 100644
--- a/src/core/dbus-slice.c
+++ b/src/core/dbus-slice.c
@@ -22,13 +22,13 @@
#include <errno.h>
#include "dbus-unit.h"
-#include "dbus-slice.h"
#include "dbus-common.h"
+#include "dbus-cgroup.h"
#include "selinux-access.h"
+#include "dbus-slice.h"
#define BUS_SLICE_INTERFACE \
" <interface name=\"org.freedesktop.systemd1.Slice\">\n" \
- BUS_UNIT_CGROUP_INTERFACE \
" </interface>\n"
#define INTROSPECTION \
@@ -48,9 +48,11 @@
const char bus_slice_interface[] _introspect_("Slice") = BUS_SLICE_INTERFACE;
DBusHandlerResult bus_slice_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
+ Slice *s = SLICE(u);
+
const BusBoundProperties bps[] = {
- { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
- { "org.freedesktop.systemd1.Slice", bus_unit_cgroup_properties, u },
+ { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
+ { "org.freedesktop.systemd1.Slice", bus_cgroup_context_properties, &s->cgroup_context },
{ NULL, }
};
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
index 973f905149..7ec4f33924 100644
--- a/src/core/dbus-socket.c
+++ b/src/core/dbus-socket.c
@@ -22,11 +22,12 @@
#include <errno.h>
#include "dbus-unit.h"
-#include "dbus-socket.h"
#include "dbus-execute.h"
#include "dbus-kill.h"
+#include "dbus-cgroup.h"
#include "dbus-common.h"
#include "selinux-access.h"
+#include "dbus-socket.h"
#define BUS_SOCKET_INTERFACE \
" <interface name=\"org.freedesktop.systemd1.Socket\">\n" \
@@ -39,7 +40,6 @@
BUS_EXEC_COMMAND_INTERFACE("ExecStopPost") \
BUS_EXEC_CONTEXT_INTERFACE \
BUS_KILL_CONTEXT_INTERFACE \
- BUS_UNIT_CGROUP_INTERFACE \
" <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
" <property name=\"BindToDevice\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
@@ -201,11 +201,11 @@ static const BusProperty bus_socket_properties[] = {
DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
Socket *s = SOCKET(u);
const BusBoundProperties bps[] = {
- { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
- { "org.freedesktop.systemd1.Socket", bus_socket_properties, s },
- { "org.freedesktop.systemd1.Socket", bus_exec_context_properties, &s->exec_context },
- { "org.freedesktop.systemd1.Socket", bus_kill_context_properties, &s->kill_context },
- { "org.freedesktop.systemd1.Socket", bus_unit_cgroup_properties, u },
+ { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
+ { "org.freedesktop.systemd1.Socket", bus_socket_properties, s },
+ { "org.freedesktop.systemd1.Socket", bus_exec_context_properties, &s->exec_context },
+ { "org.freedesktop.systemd1.Socket", bus_kill_context_properties, &s->kill_context },
+ { "org.freedesktop.systemd1.Socket", bus_cgroup_context_properties, &s->cgroup_context },
{ NULL, }
};
diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c
index 2e99fba7db..4ae1cd08e0 100644
--- a/src/core/dbus-swap.c
+++ b/src/core/dbus-swap.c
@@ -23,11 +23,12 @@
#include <errno.h>
#include "dbus-unit.h"
-#include "dbus-swap.h"
#include "dbus-execute.h"
#include "dbus-kill.h"
+#include "dbus-cgroup.h"
#include "dbus-common.h"
#include "selinux-access.h"
+#include "dbus-swap.h"
#define BUS_SWAP_INTERFACE \
" <interface name=\"org.freedesktop.systemd1.Swap\">\n" \
@@ -38,7 +39,6 @@
BUS_EXEC_COMMAND_INTERFACE("ExecDeactivate") \
BUS_EXEC_CONTEXT_INTERFACE \
BUS_KILL_CONTEXT_INTERFACE \
- BUS_UNIT_CGROUP_INTERFACE \
" <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
" <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \
" </interface>\n"
@@ -103,11 +103,11 @@ static const BusProperty bus_swap_properties[] = {
DBusHandlerResult bus_swap_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
Swap *s = SWAP(u);
const BusBoundProperties bps[] = {
- { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
- { "org.freedesktop.systemd1.Swap", bus_swap_properties, s },
- { "org.freedesktop.systemd1.Swap", bus_exec_context_properties, &s->exec_context },
- { "org.freedesktop.systemd1.Swap", bus_kill_context_properties, &s->kill_context },
- { "org.freedesktop.systemd1.Swap", bus_unit_cgroup_properties, u },
+ { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
+ { "org.freedesktop.systemd1.Swap", bus_swap_properties, s },
+ { "org.freedesktop.systemd1.Swap", bus_exec_context_properties, &s->exec_context },
+ { "org.freedesktop.systemd1.Swap", bus_kill_context_properties, &s->kill_context },
+ { "org.freedesktop.systemd1.Swap", bus_cgroup_context_properties, &s->cgroup_context },
{ NULL, }
};
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index 8a7ab349d1..cbd41342f4 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -295,90 +295,6 @@ static int bus_unit_append_job(DBusMessageIter *i, const char *property, void *d
return 0;
}
-static int bus_unit_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- char *t;
- CGroupBonding *cgb;
- bool success;
-
- assert(i);
- assert(property);
- assert(u);
-
- cgb = unit_get_default_cgroup(u);
- if (cgb) {
- t = cgroup_bonding_to_string(cgb);
- if (!t)
- return -ENOMEM;
- } else
- t = (char*) "";
-
- success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
-
- if (cgb)
- free(t);
-
- return success ? 0 : -ENOMEM;
-}
-
-static int bus_unit_append_cgroups(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- CGroupBonding *cgb;
- DBusMessageIter sub;
-
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
- return -ENOMEM;
-
- LIST_FOREACH(by_unit, cgb, u->cgroup_bondings) {
- _cleanup_free_ char *t = NULL;
- bool success;
-
- t = cgroup_bonding_to_string(cgb);
- if (!t)
- return -ENOMEM;
-
- success = dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &t);
- if (!success)
- return -ENOMEM;
- }
-
- if (!dbus_message_iter_close_container(i, &sub))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_unit_append_cgroup_attrs(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- CGroupAttribute *a;
- DBusMessageIter sub, sub2;
-
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sss)", &sub))
- return -ENOMEM;
-
- LIST_FOREACH(by_unit, a, u->cgroup_attributes) {
- _cleanup_free_ char *v = NULL;
- bool success;
-
- if (a->semantics && a->semantics->map_write)
- a->semantics->map_write(a->semantics, a->value, &v);
-
- success =
- dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) &&
- dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->controller) &&
- dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->name) &&
- dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, v ? &v : &a->value) &&
- dbus_message_iter_close_container(&sub, &sub2);
- if (!success)
- return -ENOMEM;
- }
-
- if (!dbus_message_iter_close_container(i, &sub))
- return -ENOMEM;
-
- return 0;
-}
-
static int bus_unit_append_need_daemon_reload(DBusMessageIter *i, const char *property, void *data) {
Unit *u = data;
dbus_bool_t b;
@@ -488,90 +404,6 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn
if (!reply)
goto oom;
- } else if (streq_ptr(dbus_message_get_member(message), "SetControlGroup")) {
- DBusMessageIter iter;
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
-
- if (!dbus_message_iter_init(message, &iter))
- goto oom;
-
- r = bus_unit_cgroup_set(u, &iter);
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- } else if (streq_ptr(dbus_message_get_member(message), "UnsetControlGroup")) {
- DBusMessageIter iter;
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
-
- if (!dbus_message_iter_init(message, &iter))
- goto oom;
-
- r = bus_unit_cgroup_unset(u, &iter);
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
- } else if (streq_ptr(dbus_message_get_member(message), "GetControlGroupAttribute")) {
- DBusMessageIter iter;
- _cleanup_strv_free_ char **list = NULL;
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
-
- if (!dbus_message_iter_init(message, &iter))
- goto oom;
-
- r = bus_unit_cgroup_attribute_get(u, &iter, &list);
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- dbus_message_iter_init_append(reply, &iter);
- if (bus_append_strv_iter(&iter, list) < 0)
- goto oom;
-
- } else if (streq_ptr(dbus_message_get_member(message), "SetControlGroupAttribute")) {
- DBusMessageIter iter;
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
-
- if (!dbus_message_iter_init(message, &iter))
- goto oom;
-
- r = bus_unit_cgroup_attribute_set(u, &iter);
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- } else if (streq_ptr(dbus_message_get_member(message), "UnsetControlGroupAttribute")) {
- DBusMessageIter iter;
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
-
- if (!dbus_message_iter_init(message, &iter))
- goto oom;
-
- r = bus_unit_cgroup_attribute_unset(u, &iter);
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
} else if (UNIT_VTABLE(u)->bus_message_handler)
return UNIT_VTABLE(u)->bus_message_handler(u, connection, message);
else
@@ -913,360 +745,6 @@ oom:
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
-static int parse_mode(DBusMessageIter *iter, bool *runtime, bool next) {
- const char *mode;
- int r;
-
- assert(iter);
- assert(runtime);
-
- r = bus_iter_get_basic_and_next(iter, DBUS_TYPE_STRING, &mode, next);
- if (r < 0)
- return r;
-
- if (streq(mode, "runtime"))
- *runtime = true;
- else if (streq(mode, "persistent"))
- *runtime = false;
- else
- return -EINVAL;
-
- return 0;
-}
-
-int bus_unit_cgroup_set(Unit *u, DBusMessageIter *iter) {
- _cleanup_free_ char *controller = NULL, *old_path = NULL, *new_path = NULL, *contents = NULL;
- const char *name;
- CGroupBonding *b;
- bool runtime;
- int r;
-
- assert(u);
- assert(iter);
-
- if (!unit_get_exec_context(u))
- return -EINVAL;
-
- r = bus_iter_get_basic_and_next(iter, DBUS_TYPE_STRING, &name, true);
- if (r < 0)
- return r;
-
- r = parse_mode(iter, &runtime, false);
- if (r < 0)
- return r;
-
- r = cg_split_spec(name, &controller, &new_path);
- if (r < 0)
- return r;
-
- if (!new_path) {
- new_path = unit_default_cgroup_path(u);
- if (!new_path)
- return -ENOMEM;
- }
-
- if (!controller || streq(controller, SYSTEMD_CGROUP_CONTROLLER))
- return -EINVAL;
-
- b = cgroup_bonding_find_list(u->cgroup_bondings, controller);
- if (b) {
- if (streq(b->path, new_path))
- return 0;
-
- if (b->essential)
- return -EINVAL;
-
- old_path = strdup(b->path);
- if (!old_path)
- return -ENOMEM;
- }
-
- r = unit_add_cgroup_from_text(u, name, true, &b);
- if (r < 0)
- return r;
- if (r > 0) {
- CGroupAttribute *a;
-
- /* Try to move things to the new place, and clean up the old place */
- cgroup_bonding_realize(b);
- cgroup_bonding_migrate(b, u->cgroup_bondings);
-
- if (old_path)
- cg_trim(controller, old_path, true);
-
- /* Apply the attributes to the new group */
- LIST_FOREACH(by_unit, a, u->cgroup_attributes)
- if (streq(a->controller, controller))
- cgroup_attribute_apply(a, b);
- }
-
- contents = strjoin("[", UNIT_VTABLE(u)->exec_section, "]\n"
- "ControlGroup=", name, "\n", NULL);
- if (!contents)
- return -ENOMEM;
-
- return unit_write_drop_in(u, runtime, controller, contents);
-}
-
-int bus_unit_cgroup_unset(Unit *u, DBusMessageIter *iter) {
- _cleanup_free_ char *controller = NULL, *path = NULL, *target = NULL;
- const char *name;
- CGroupAttribute *a, *n;
- CGroupBonding *b;
- bool runtime;
- int r;
-
- assert(u);
- assert(iter);
-
- if (!unit_get_exec_context(u))
- return -EINVAL;
-
- r = bus_iter_get_basic_and_next(iter, DBUS_TYPE_STRING, &name, true);
- if (r < 0)
- return r;
-
- r = parse_mode(iter, &runtime, false);
- if (r < 0)
- return r;
-
- r = cg_split_spec(name, &controller, &path);
- if (r < 0)
- return r;
-
- if (!controller || streq(controller, SYSTEMD_CGROUP_CONTROLLER))
- return -EINVAL;
-
- b = cgroup_bonding_find_list(u->cgroup_bondings, controller);
- if (!b)
- return -ENOENT;
-
- if (path && !path_equal(path, b->path))
- return -ENOENT;
-
- if (b->essential)
- return -EINVAL;
-
- unit_remove_drop_in(u, runtime, controller);
-
- /* Try to migrate the old group away */
- if (cg_pid_get_path(controller, 0, &target) >= 0)
- cgroup_bonding_migrate_to(u->cgroup_bondings, target, false);
-
- cgroup_bonding_free(b, true);
-
- /* Drop all attributes of this controller */
- LIST_FOREACH_SAFE(by_unit, a, n, u->cgroup_attributes) {
- if (!streq(a->controller, controller))
- continue;
-
- unit_remove_drop_in(u, runtime, a->name);
- cgroup_attribute_free(a);
- }
-
- return 0;
-}
-
-int bus_unit_cgroup_attribute_get(Unit *u, DBusMessageIter *iter, char ***_result) {
- _cleanup_free_ char *controller = NULL;
- CGroupAttribute *a;
- CGroupBonding *b;
- const char *name;
- char **l = NULL;
- int r;
-
- assert(u);
- assert(iter);
- assert(_result);
-
- if (!unit_get_exec_context(u))
- return -EINVAL;
-
- r = bus_iter_get_basic_and_next(iter, DBUS_TYPE_STRING, &name, false);
- if (r < 0)
- return r;
-
- r = cg_controller_from_attr(name, &controller);
- if (r < 0)
- return r;
-
- /* First attempt, read the value from the kernel */
- b = cgroup_bonding_find_list(u->cgroup_bondings, controller);
- if (b) {
- _cleanup_free_ char *p = NULL, *v = NULL;
-
- r = cg_get_path(b->controller, b->path, name, &p);
- if (r < 0)
- return r;
-
- r = read_full_file(p, &v, NULL);
- if (r >= 0) {
- /* Split on new lines */
- l = strv_split_newlines(v);
- if (!l)
- return -ENOMEM;
-
- *_result = l;
- return 0;
-
- }
- }
-
- /* If that didn't work, read our cached value */
- LIST_FOREACH(by_unit, a, u->cgroup_attributes) {
-
- if (!cgroup_attribute_matches(a, controller, name))
- continue;
-
- r = strv_extend(&l, a->value);
- if (r < 0) {
- strv_free(l);
- return r;
- }
- }
-
- if (!l)
- return -ENOENT;
-
- *_result = l;
- return 0;
-}
-
-static int update_attribute_drop_in(Unit *u, bool runtime, const char *name) {
- _cleanup_free_ char *buf = NULL;
- CGroupAttribute *a;
-
- assert(u);
- assert(name);
-
- LIST_FOREACH(by_unit, a, u->cgroup_attributes) {
- if (!cgroup_attribute_matches(a, NULL, name))
- continue;
-
- if (!buf) {
- buf = strjoin("[", UNIT_VTABLE(u)->exec_section, "]\n"
- "ControlGroupAttribute=", a->name, " ", a->value, "\n", NULL);
-
- if (!buf)
- return -ENOMEM;
- } else {
- char *b;
-
- b = strjoin(buf,
- "ControlGroupAttribute=", a->name, " ", a->value, "\n", NULL);
-
- if (!b)
- return -ENOMEM;
-
- free(buf);
- buf = b;
- }
- }
-
- if (buf)
- return unit_write_drop_in(u, runtime, name, buf);
- else
- return unit_remove_drop_in(u, runtime, name);
-}
-
-int bus_unit_cgroup_attribute_set(Unit *u, DBusMessageIter *iter) {
- _cleanup_strv_free_ char **l = NULL;
- int r;
- bool runtime = false;
- char **value;
- const char *name;
-
- assert(u);
- assert(iter);
-
- if (!unit_get_exec_context(u))
- return -EINVAL;
-
- r = bus_iter_get_basic_and_next(iter, DBUS_TYPE_STRING, &name, true);
- if (r < 0)
- return r;
-
- r = bus_parse_strv_iter(iter, &l);
- if (r < 0)
- return r;
-
- if (!dbus_message_iter_next(iter))
- return -EINVAL;
-
- r = parse_mode(iter, &runtime, false);
- if (r < 0)
- return r;
-
- STRV_FOREACH(value, l) {
- _cleanup_free_ char *v = NULL;
- CGroupAttribute *a;
- const CGroupSemantics *s;
-
- r = cgroup_semantics_find(NULL, name, *value, &v, &s);
- if (r < 0)
- return r;
-
- if (s && !s->multiple && l[1])
- return -EINVAL;
-
- r = unit_add_cgroup_attribute(u, s, NULL, name, v ? v : *value, &a);
- if (r < 0)
- return r;
-
- if (r > 0) {
- CGroupBonding *b;
-
- b = cgroup_bonding_find_list(u->cgroup_bondings, a->controller);
- if (!b) {
- /* Doesn't exist yet? Then let's add it */
- r = unit_add_cgroup_from_text(u, a->controller, false, &b);
- if (r < 0)
- return r;
-
- if (r > 0) {
- cgroup_bonding_realize(b);
- cgroup_bonding_migrate(b, u->cgroup_bondings);
- }
- }
-
- /* Make it count */
- cgroup_attribute_apply(a, u->cgroup_bondings);
- }
-
- }
-
- r = update_attribute_drop_in(u, runtime, name);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int bus_unit_cgroup_attribute_unset(Unit *u, DBusMessageIter *iter) {
- const char *name;
- bool runtime;
- int r;
-
- assert(u);
- assert(iter);
-
- if (!unit_get_exec_context(u))
- return -EINVAL;
-
- r = bus_iter_get_basic_and_next(iter, DBUS_TYPE_STRING, &name, true);
- if (r < 0)
- return r;
-
- r = parse_mode(iter, &runtime, false);
- if (r < 0)
- return r;
-
- cgroup_attribute_free_some(u->cgroup_attributes, NULL, name);
- update_attribute_drop_in(u, runtime, name);
-
- return 0;
-}
-
const BusProperty bus_unit_properties[] = {
{ "Id", bus_property_append_string, "s", offsetof(Unit, id), true },
{ "Names", bus_unit_append_names, "as", 0 },
@@ -1330,12 +808,6 @@ const BusProperty bus_unit_properties[] = {
{ "ConditionTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, condition_timestamp.monotonic) },
{ "ConditionResult", bus_property_append_bool, "b", offsetof(Unit, condition_result) },
{ "LoadError", bus_unit_append_load_error, "(ss)", 0 },
- { NULL, }
-};
-
-const BusProperty bus_unit_cgroup_properties[] = {
- { "DefaultControlGroup", bus_unit_append_default_cgroup, "s", 0 },
- { "ControlGroups", bus_unit_append_cgroups, "as", 0 },
- { "ControlGroupAttributes", bus_unit_append_cgroup_attrs, "a(sss)", 0 },
+ { "ControlGroup", bus_property_append_string, "s", offsetof(Unit, cgroup_path), true },
{ NULL, }
};
diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h
index 83932c5a6c..1e226ef451 100644
--- a/src/core/dbus-unit.h
+++ b/src/core/dbus-unit.h
@@ -123,40 +123,14 @@
" <property name=\"ConditionTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
" <property name=\"ConditionResult\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"LoadError\" type=\"(ss)\" access=\"read\"/>\n" \
+ " <property name=\"ControlGroup\" type=\"s\" access=\"read\"/>\n" \
" </interface>\n"
-#define BUS_UNIT_CGROUP_INTERFACE \
- " <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"ControlGroups\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"ControlGroupAttributes\" type=\"a(sss)\" access=\"read\"/>\n" \
- " <method name=\"SetControlGroup\">\n" \
- " <arg name=\"group\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " </method>\n" \
- " <method name=\"UnsetControlGroup\">\n" \
- " <arg name=\"group\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " </method>\n" \
- " <method name=\"GetControlGroupAttribute\">\n" \
- " <arg name=\"attribute\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"values\" type=\"as\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"SetControlGroupAttribute\">\n" \
- " <arg name=\"attribute\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"values\" type=\"as\" direction=\"in\"/>\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " </method>\n" \
- " <method name=\"UnsetControlGroupAttribute\">\n" \
- " <arg name=\"attribute\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " </method>\n"
-
#define BUS_UNIT_INTERFACES_LIST \
BUS_GENERIC_INTERFACES_LIST \
"org.freedesktop.systemd1.Unit\0"
extern const BusProperty bus_unit_properties[];
-extern const BusProperty bus_unit_cgroup_properties[];
void bus_unit_send_change_signal(Unit *u);
void bus_unit_send_removed_signal(Unit *u);
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 1272c938cf..c2097a4dbf 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -28,7 +28,6 @@
#include "dbus.h"
#include "log.h"
#include "strv.h"
-#include "cgroup.h"
#include "mkdir.h"
#include "missing.h"
#include "dbus-unit.h"
@@ -453,7 +452,7 @@ static DBusHandlerResult system_bus_message_filter(DBusConnection *connection, D
DBUS_TYPE_INVALID))
log_error("Failed to parse Released message: %s", bus_error_message(&error));
else
- cgroup_notify_empty(m, cgroup);
+ manager_notify_cgroup_empty(m, cgroup);
}
dbus_error_free(&error);
@@ -489,7 +488,7 @@ static DBusHandlerResult private_bus_message_filter(DBusConnection *connection,
DBUS_TYPE_INVALID))
log_error("Failed to parse Released message: %s", bus_error_message(&error));
else
- cgroup_notify_empty(m, cgroup);
+ manager_notify_cgroup_empty(m, cgroup);
/* Forward the message to the system bus, so that user
* instances are notified as well */
diff --git a/src/core/execute.c b/src/core/execute.c
index 9148d06df4..5e342f8d47 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -55,7 +55,6 @@
#include "sd-messages.h"
#include "ioprio.h"
#include "securebits.h"
-#include "cgroup.h"
#include "namespace.h"
#include "tcpwrap.h"
#include "exit-status.h"
@@ -67,6 +66,7 @@
#include "syscall-list.h"
#include "env-util.h"
#include "fileio.h"
+#include "unit.h"
#define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
@@ -986,18 +986,17 @@ int exec_spawn(ExecCommand *command,
bool apply_chroot,
bool apply_tty_stdin,
bool confirm_spawn,
- CGroupBonding *cgroup_bondings,
- CGroupAttribute *cgroup_attributes,
- const char *cgroup_suffix,
+ CGroupControllerMask cgroup_mask,
+ const char *cgroup_path,
const char *unit_id,
int idle_pipe[2],
pid_t *ret) {
+ _cleanup_strv_free_ char **files_env = NULL;
+ int socket_fd;
+ char *line;
pid_t pid;
int r;
- char *line;
- int socket_fd;
- _cleanup_strv_free_ char **files_env = NULL;
assert(command);
assert(context);
@@ -1042,17 +1041,6 @@ int exec_spawn(ExecCommand *command,
NULL);
free(line);
- r = cgroup_bonding_realize_list(cgroup_bondings);
- if (r < 0)
- return r;
-
- /* We must initialize the attributes in the parent, before we
- fork, because we really need them initialized before making
- the process a member of the group (which we do in both the
- child and the parent), and we cannot really apply them twice
- (due to 'append' style attributes) */
- cgroup_attribute_apply_list(cgroup_attributes, cgroup_bondings);
-
if (context->private_tmp && !context->tmp_dir && !context->var_tmp_dir) {
r = setup_tmpdirs(&context->tmp_dir, &context->var_tmp_dir);
if (r < 0)
@@ -1072,7 +1060,6 @@ int exec_spawn(ExecCommand *command,
_cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL,
**final_env = NULL, **final_argv = NULL;
unsigned n_env = 0;
- bool set_access = false;
/* child */
@@ -1185,8 +1172,8 @@ int exec_spawn(ExecCommand *command,
goto fail_child;
}
- if (cgroup_bondings) {
- err = cgroup_bonding_install_list(cgroup_bondings, 0, cgroup_suffix);
+ if (cgroup_path) {
+ err = cg_attach_with_mask(cgroup_mask, cgroup_path, 0);
if (err < 0) {
r = EXIT_CGROUP;
goto fail_child;
@@ -1269,36 +1256,6 @@ int exec_spawn(ExecCommand *command,
goto fail_child;
}
}
-
- if (cgroup_bondings && context->control_group_modify) {
- err = cgroup_bonding_set_group_access_list(cgroup_bondings, 0755, uid, gid);
- if (err >= 0)
- err = cgroup_bonding_set_task_access_list(
- cgroup_bondings,
- 0644,
- uid,
- gid,
- context->control_group_persistent);
- if (err < 0) {
- r = EXIT_CGROUP;
- goto fail_child;
- }
-
- set_access = true;
- }
- }
-
- if (cgroup_bondings && !set_access && context->control_group_persistent >= 0) {
- err = cgroup_bonding_set_task_access_list(
- cgroup_bondings,
- (mode_t) -1,
- (uid_t) -1,
- (uid_t) -1,
- context->control_group_persistent);
- if (err < 0) {
- r = EXIT_CGROUP;
- goto fail_child;
- }
}
if (apply_permissions) {
@@ -1562,7 +1519,8 @@ int exec_spawn(ExecCommand *command,
* outside of the cgroup) and in the parent (so that we can be
* sure that when we kill the cgroup the process will be
* killed too). */
- cgroup_bonding_install_list(cgroup_bondings, pid, cgroup_suffix);
+ if (cgroup_path)
+ cg_attach(SYSTEMD_CGROUP_CONTROLLER, cgroup_path, pid);
exec_status_start(&command->exec_status, pid);
@@ -1578,7 +1536,6 @@ void exec_context_init(ExecContext *c) {
c->cpu_sched_policy = SCHED_OTHER;
c->syslog_priority = LOG_DAEMON|LOG_INFO;
c->syslog_level_prefix = true;
- c->control_group_persistent = -1;
c->ignore_sigpipe = true;
c->timer_slack_nsec = (nsec_t) -1;
}
@@ -1843,8 +1800,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
assert(c);
assert(f);
- if (!prefix)
- prefix = "";
+ prefix = strempty(prefix);
fprintf(f,
"%sUMask: %04o\n"
@@ -1852,8 +1808,6 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
"%sRootDirectory: %s\n"
"%sNonBlocking: %s\n"
"%sPrivateTmp: %s\n"
- "%sControlGroupModify: %s\n"
- "%sControlGroupPersistent: %s\n"
"%sPrivateNetwork: %s\n"
"%sIgnoreSIGPIPE: %s\n",
prefix, c->umask,
@@ -1861,8 +1815,6 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
prefix, c->root_directory ? c->root_directory : "/",
prefix, yes_no(c->non_blocking),
prefix, yes_no(c->private_tmp),
- prefix, yes_no(c->control_group_modify),
- prefix, yes_no(c->control_group_persistent),
prefix, yes_no(c->private_network),
prefix, yes_no(c->ignore_sigpipe));
diff --git a/src/core/execute.h b/src/core/execute.h
index 15574dc97e..c1e9717dc8 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -33,14 +33,11 @@ typedef struct ExecContext ExecContext;
#include <stdio.h>
#include <sched.h>
-struct CGroupBonding;
-struct CGroupAttribute;
-
-typedef struct Unit Unit;
-
#include "list.h"
#include "util.h"
+typedef struct Unit Unit;
+
typedef enum ExecInput {
EXEC_INPUT_NULL,
EXEC_INPUT_TTY,
@@ -148,9 +145,6 @@ struct ExecContext {
bool no_new_privileges;
- bool control_group_modify;
- int control_group_persistent;
-
/* This is not exposed to the user but available
* internally. We need it to make sure that whenever we spawn
* /bin/mount it is run in the same process group as us so
@@ -166,6 +160,8 @@ struct ExecContext {
bool cpu_sched_set:1;
};
+#include "cgroup.h"
+
int exec_spawn(ExecCommand *command,
char **argv,
ExecContext *context,
@@ -175,9 +171,8 @@ int exec_spawn(ExecCommand *command,
bool apply_chroot,
bool apply_tty_stdin,
bool confirm_spawn,
- struct CGroupBonding *cgroup_bondings,
- struct CGroupAttribute *cgroup_attributes,
- const char *cgroup_suffix,
+ CGroupControllerMask cgroup_mask,
+ const char *cgroup_path,
const char *unit_id,
int pipe_fd[2],
pid_t *ret);
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 9e5a408a30..aa07de0517 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -75,9 +75,7 @@ $1.MountFlags, config_parse_exec_mount_flags, 0,
$1.TCPWrapName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.tcpwrap_name)
$1.PAMName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.pam_name)
$1.IgnoreSIGPIPE, config_parse_bool, 0, offsetof($1, exec_context.ignore_sigpipe)
-$1.UtmpIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.utmp_id)
-$1.ControlGroupModify, config_parse_bool, 0, offsetof($1, exec_context.control_group_modify)
-$1.ControlGroupPersistent, config_parse_tristate, 0, offsetof($1, exec_context.control_group_persistent)'
+$1.UtmpIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.utmp_id)'
)m4_dnl
m4_define(`KILL_CONTEXT_CONFIG_ITEMS',
`$1.SendSIGKILL, config_parse_bool, 0, offsetof($1, kill_context.send_sigkill)
@@ -85,16 +83,17 @@ $1.KillMode, config_parse_kill_mode, 0,
$1.KillSignal, config_parse_kill_signal, 0, offsetof($1, kill_context.kill_signal)'
)m4_dnl
m4_define(`CGROUP_CONTEXT_CONFIG_ITEMS',
-`$1.ControlGroup, config_parse_unit_cgroup, 0, 0
-$1.ControlGroupAttribute, config_parse_unit_cgroup_attr, 0, 0
-$1.CPUShares, config_parse_unit_cgroup_attr_pretty, 0, 0
-$1.MemoryLimit, config_parse_unit_cgroup_attr_pretty, 0, 0
-$1.MemorySoftLimit, config_parse_unit_cgroup_attr_pretty, 0, 0
-$1.DeviceAllow, config_parse_unit_cgroup_attr_pretty, 0, 0
-$1.DeviceDeny, config_parse_unit_cgroup_attr_pretty, 0, 0
-$1.BlockIOWeight, config_parse_unit_cgroup_attr_pretty, 0, 0
-$1.BlockIOReadBandwidth, config_parse_unit_cgroup_attr_pretty, 0, 0
-$1.BlockIOWriteBandwidth, config_parse_unit_cgroup_attr_pretty, 0, 0'
+`$1.CPUAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.cpu_accounting)
+$1.CPUShares, config_parse_cpu_shares, 0, offsetof($1, cgroup_context)
+$1.MemoryAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.memory_accounting)
+$1.MemoryLimit, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
+$1.MemorySoftLimit, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
+$1.DeviceAllow, config_parse_device_allow, 0, offsetof($1, cgroup_context)
+$1.DevicePolicy, config_parse_device_policy, 0, offsetof($1, cgroup_context.device_policy)
+$1.BlockIOAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.blockio_accounting)
+$1.BlockIOWeight, config_parse_blockio_weight, 0, offsetof($1, cgroup_context)
+$1.BlockIOReadBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
+$1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)'
)m4_dnl
Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description)
Unit.Documentation, config_parse_documentation, 0, offsetof(Unit, documentation)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 15fabe860e..57c8156fdd 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -51,6 +51,7 @@
#include "path-util.h"
#include "syscall-list.h"
#include "env-util.h"
+#include "cgroup.h"
#ifndef HAVE_SYSV_COMPAT
int config_parse_warn_compat(const char *unit,
@@ -996,58 +997,6 @@ int config_parse_limit(const char *unit,
return 0;
}
-int config_parse_unit_cgroup(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Unit *u = userdata;
- char *w;
- size_t l;
- char *state;
-
- if (isempty(rvalue)) {
- /* An empty assignment resets the list */
- cgroup_bonding_free_list(u->cgroup_bondings, false);
- u->cgroup_bondings = NULL;
- return 0;
- }
-
- FOREACH_WORD_QUOTED(w, l, rvalue, state) {
- _cleanup_free_ char *t = NULL, *k = NULL, *ku = NULL;
- int r;
-
- t = strndup(w, l);
- if (!t)
- return log_oom();
-
- k = unit_full_printf(u, t);
- if (!k)
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to resolve unit specifiers on %s. Ignoring.",
- t);
-
- ku = cunescape(k ? k : t);
- if (!ku)
- return log_oom();
-
- r = unit_add_cgroup_from_text(u, ku, true, NULL);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse cgroup value %s, ignoring: %s",
- k, rvalue);
- return 0;
- }
- }
-
- return 0;
-}
-
#ifdef HAVE_SYSV_COMPAT
int config_parse_sysv_priority(const char *unit,
const char *filename,
@@ -1793,108 +1742,6 @@ int config_parse_unit_condition_null(const char *unit,
DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
-int config_parse_unit_cgroup_attr(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Unit *u = data;
- size_t a, b;
- _cleanup_free_ char *n = NULL, *v = NULL;
- const CGroupSemantics *s;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* Empty assignment clears the list */
- cgroup_attribute_free_list(u->cgroup_attributes);
- u->cgroup_attributes = NULL;
- return 0;
- }
-
- a = strcspn(rvalue, WHITESPACE);
- b = strspn(rvalue + a, WHITESPACE);
- if (a <= 0 || b <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse cgroup attribute value, ignoring: %s",
- rvalue);
- return 0;
- }
-
- n = strndup(rvalue, a);
- if (!n)
- return log_oom();
-
- r = cgroup_semantics_find(NULL, n, rvalue + a + b, &v, &s);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse cgroup attribute value, ignoring: %s",
- rvalue);
- return 0;
- }
-
- r = unit_add_cgroup_attribute(u, s, NULL, n, v ? v : rvalue + a + b, NULL);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to add cgroup attribute value, ignoring: %s", rvalue);
- return 0;
- }
-
- return 0;
-}
-
-int config_parse_unit_cgroup_attr_pretty(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Unit *u = data;
- _cleanup_free_ char *v = NULL;
- const CGroupSemantics *s;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = cgroup_semantics_find(NULL, lvalue, rvalue, &v, &s);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse cgroup attribute value, ignoring: %s",
- rvalue);
- return 0;
- } else if (r == 0) {
- log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
- "Unknown or unsupported cgroup attribute %s, ignoring: %s",
- lvalue, rvalue);
- return 0;
- }
-
- r = unit_add_cgroup_attribute(u, s, NULL, NULL, v, NULL);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to add cgroup attribute value, ignoring: %s", rvalue);
- return 0;
- }
-
- return 0;
-}
-
int config_parse_unit_requires_mounts_for(const char *unit,
const char *filename,
unsigned line,
@@ -2104,6 +1951,285 @@ int config_parse_unit_slice(
return 0;
}
+DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
+
+int config_parse_cpu_shares(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ CGroupContext *c = data;
+ unsigned long lu;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ c->cpu_shares = 1024;
+ return 0;
+ }
+
+ r = safe_atolu(rvalue, &lu);
+ if (r < 0 || lu <= 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "CPU shares '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ c->cpu_shares = lu;
+ return 0;
+}
+
+int config_parse_memory_limit(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ CGroupContext *c = data;
+ uint64_t *limit;
+ off_t bytes;
+ int r;
+
+ limit = streq(lvalue, "MemoryLimit") ? &c->memory_limit : &c->memory_soft_limit;
+
+ if (isempty(rvalue)) {
+ *limit = (uint64_t) -1;
+ return 0;
+ }
+
+ assert_cc(sizeof(uint64_t) == sizeof(off_t));
+
+ r = parse_bytes(rvalue, &bytes);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Memory limit '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ *limit = (uint64_t) bytes;
+ return 0;
+}
+
+int config_parse_device_allow(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_free_ char *path = NULL;
+ CGroupContext *c = data;
+ CGroupDeviceAllow *a;
+ const char *m;
+ size_t n;
+
+ if (isempty(rvalue)) {
+ while (c->device_allow)
+ cgroup_context_free_device_allow(c, c->device_allow);
+
+ return 0;
+ }
+
+ n = strcspn(rvalue, WHITESPACE);
+ path = strndup(rvalue, n);
+ if (!path)
+ return log_oom();
+
+ if (!path_startswith(path, "/dev")) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Invalid device node path '%s'. Ignoring.", path);
+ return 0;
+ }
+
+ m = rvalue + n + strspn(rvalue + n, WHITESPACE);
+ if (isempty(m))
+ m = "rwm";
+
+ if (!in_charset(m, "rwm")) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Invalid device rights '%s'. Ignoring.", m);
+ return 0;
+ }
+
+ a = new0(CGroupDeviceAllow, 1);
+ if (!a)
+ return log_oom();
+
+ a->path = path;
+ path = NULL;
+ a->r = !!strchr(m, 'r');
+ a->w = !!strchr(m, 'w');
+ a->m = !!strchr(m, 'm');
+
+ LIST_PREPEND(CGroupDeviceAllow, device_allow, c->device_allow, a);
+ return 0;
+}
+
+int config_parse_blockio_weight(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_free_ char *path = NULL;
+ CGroupContext *c = data;
+ unsigned long lu;
+ const char *weight;
+ size_t n;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ c->blockio_weight = 1000;
+
+ while (c->blockio_device_weights)
+ cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
+
+ return 0;
+ }
+
+ n = strcspn(rvalue, WHITESPACE);
+ weight = rvalue + n;
+ if (*weight) {
+ /* Two params, first device name, then weight */
+ path = strndup(rvalue, n);
+ if (!path)
+ return log_oom();
+
+ if (!path_startswith(path, "/dev")) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Invalid device node path '%s'. Ignoring.", path);
+ return 0;
+ }
+
+ weight += strspn(weight, WHITESPACE);
+ } else
+ /* One param, only weight */
+ weight = rvalue;
+
+ r = safe_atolu(weight, &lu);
+ if (r < 0 || lu < 10 || lu > 1000) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Block IO weight '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ if (!path)
+ c->blockio_weight = lu;
+ else {
+ CGroupBlockIODeviceWeight *w;
+
+ w = new0(CGroupBlockIODeviceWeight, 1);
+ if (!w)
+ return log_oom();
+
+ w->path = path;
+ path = NULL;
+
+ w->weight = lu;
+
+ LIST_PREPEND(CGroupBlockIODeviceWeight, device_weights, c->blockio_device_weights, w);
+ }
+
+ return 0;
+}
+
+int config_parse_blockio_bandwidth(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_free_ char *path = NULL;
+ CGroupBlockIODeviceBandwidth *b;
+ CGroupContext *c = data;
+ const char *bandwidth;
+ off_t bytes;
+ size_t n;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ while (c->blockio_device_bandwidths)
+ cgroup_context_free_blockio_device_bandwidth(c, c->blockio_device_bandwidths);
+
+ return 0;
+ }
+
+ n = strcspn(rvalue, WHITESPACE);
+ bandwidth = rvalue + n;
+ bandwidth += strspn(bandwidth, WHITESPACE);
+
+ if (!*bandwidth) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Expected space separated pair of device node and bandwidth. Ignoring.");
+ return 0;
+ }
+
+ path = strndup(rvalue, n);
+ if (!path)
+ return log_oom();
+
+ if (!path_startswith(path, "/dev")) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Invalid device node path '%s'. Ignoring.", path);
+ return 0;
+ }
+
+ r = parse_bytes(bandwidth, &bytes);
+ if (r < 0 || bytes <= 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ b = new0(CGroupBlockIODeviceBandwidth, 1);
+ if (!b)
+ return log_oom();
+
+ b->path = path;
+ path = NULL;
+ b->bandwidth = (uint64_t) bytes;
+
+ LIST_PREPEND(CGroupBlockIODeviceBandwidth, device_bandwidths, c->blockio_device_bandwidths, b);
+
+ return 0;
+}
+
#define FOLLOW_MAX 8
static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
@@ -2463,7 +2589,6 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_exec_secure_bits, "SECUREBITS" },
{ config_parse_bounding_set, "BOUNDINGSET" },
{ config_parse_limit, "LIMIT" },
- { config_parse_unit_cgroup, "CGROUP [...]" },
{ config_parse_unit_deps, "UNIT [...]" },
{ config_parse_exec, "PATH [ARGUMENT [...]]" },
{ config_parse_service_type, "SERVICETYPE" },
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index f9677baa0f..5e36f3538a 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -55,7 +55,6 @@ int config_parse_exec_capabilities(const char *unit, const char *filename, unsig
int config_parse_exec_secure_bits(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_bounding_set(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_cgroup(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_fsck_passno(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
@@ -73,12 +72,16 @@ int config_parse_unit_condition_null(const char *unit, const char *filename, uns
int config_parse_kill_mode(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_notify_access(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_start_limit_action(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_cgroup_attr(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_cgroup_attr_pretty(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_requires_mounts_for(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_syscall_filter(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_environ(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_slice(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_cpu_shares(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_memory_limit(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_device_policy(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_device_allow(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_blockio_weight(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_blockio_bandwidth(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
/* gperf prototypes */
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);
diff --git a/src/core/main.c b/src/core/main.c
index c123de91ce..3c6fccf527 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -88,7 +88,6 @@ static int arg_crash_chvt = -1;
static bool arg_confirm_spawn = false;
static bool arg_show_status = true;
static bool arg_switched_root = false;
-static char **arg_default_controllers = NULL;
static char ***arg_join_controllers = NULL;
static ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL;
static ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT;
@@ -642,7 +641,6 @@ static int parse_config_file(void) {
{ "Manager", "ShowStatus", config_parse_bool, 0, &arg_show_status },
{ "Manager", "CrashChVT", config_parse_int, 0, &arg_crash_chvt },
{ "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, NULL },
- { "Manager", "DefaultControllers", config_parse_strv, 0, &arg_default_controllers },
{ "Manager", "DefaultStandardOutput", config_parse_output, 0, &arg_default_std_output },
{ "Manager", "DefaultStandardError", config_parse_output, 0, &arg_default_std_error },
{ "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers },
@@ -1632,9 +1630,6 @@ int main(int argc, char *argv[]) {
manager_set_default_rlimits(m, arg_default_rlimit);
- if (arg_default_controllers)
- manager_set_default_controllers(m, arg_default_controllers);
-
if (arg_default_environment)
manager_set_default_environment(m, arg_default_environment);
@@ -1807,7 +1802,6 @@ finish:
free(arg_default_rlimit[j]);
free(arg_default_unit);
- strv_free(arg_default_controllers);
free_join_controllers();
dbus_shutdown();
diff --git a/src/core/manager.c b/src/core/manager.c
index 2416dd0f1e..6ba51a4116 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -55,7 +55,6 @@
#include "util.h"
#include "mkdir.h"
#include "ratelimit.h"
-#include "cgroup.h"
#include "mount-setup.h"
#include "unit-name.h"
#include "dbus-unit.h"
@@ -467,12 +466,6 @@ int manager_new(SystemdRunningAs running_as, Manager **_m) {
manager_strip_environment(m);
- if (running_as == SYSTEMD_SYSTEM) {
- m->default_controllers = strv_new("cpu", NULL);
- if (!m->default_controllers)
- goto fail;
- }
-
if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
goto fail;
@@ -482,7 +475,8 @@ int manager_new(SystemdRunningAs running_as, Manager **_m) {
if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func)))
goto fail;
- if (!(m->cgroup_bondings = hashmap_new(string_hash_func, string_compare_func)))
+ m->cgroup_unit = hashmap_new(string_hash_func, string_compare_func);
+ if (!m->cgroup_unit)
goto fail;
if (!(m->watch_bus = hashmap_new(string_hash_func, string_compare_func)))
@@ -712,9 +706,7 @@ void manager_free(Manager *m) {
lookup_paths_free(&m->lookup_paths);
strv_free(m->environment);
- strv_free(m->default_controllers);
-
- hashmap_free(m->cgroup_bondings);
+ hashmap_free(m->cgroup_unit);
set_free_free(m->unit_path_cache);
close_pipe(m->idle_pipe);
@@ -1220,7 +1212,7 @@ static int manager_process_notify_fd(Manager *m) {
u = hashmap_get(m->watch_pids, LONG_TO_PTR(ucred->pid));
if (!u) {
- u = cgroup_unit_by_pid(m, ucred->pid);
+ u = manager_get_unit_by_pid(m, ucred->pid);
if (!u) {
log_warning("Cannot find unit for notify message of PID %lu.", (unsigned long) ucred->pid);
continue;
@@ -1285,7 +1277,7 @@ static int manager_dispatch_sigchld(Manager *m) {
/* And now figure out the unit this belongs to */
u = hashmap_get(m->watch_pids, LONG_TO_PTR(si.si_pid));
if (!u)
- u = cgroup_unit_by_pid(m, si.si_pid);
+ u = manager_get_unit_by_pid(m, si.si_pid);
/* And now, we actually reap the zombie. */
if (waitid(P_PID, si.si_pid, &si, WEXITED) < 0) {
@@ -1741,6 +1733,9 @@ int manager_loop(Manager *m) {
if (manager_dispatch_gc_queue(m) > 0)
continue;
+ if (manager_dispatch_cgroup_queue(m) > 0)
+ continue;
+
if (manager_dispatch_dbus_queue(m) > 0)
continue;
@@ -2586,23 +2581,6 @@ int manager_set_default_environment(Manager *m, char **environment) {
return 0;
}
-int manager_set_default_controllers(Manager *m, char **controllers) {
- char **l;
-
- assert(m);
-
- l = strv_copy(controllers);
- if (!l)
- return -ENOMEM;
-
- strv_free(m->default_controllers);
- m->default_controllers = l;
-
- cg_shorten_controllers(m->default_controllers);
-
- return 0;
-}
-
int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) {
int i;
diff --git a/src/core/manager.h b/src/core/manager.h
index f0bb2eb035..68cb2e4a3d 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -27,6 +27,7 @@
#include <dbus/dbus.h>
#include "fdset.h"
+#include "cgroup-util.h"
/* Enforce upper limit how many names we allow */
#define MANAGER_MAX_NAMES 131072 /* 128K */
@@ -86,6 +87,7 @@ struct Watch {
#include "dbus.h"
#include "path-lookup.h"
#include "execute.h"
+#include "unit-name.h"
struct Manager {
/* Note that the set of units we know of is allowed to be
@@ -122,6 +124,9 @@ struct Manager {
/* Units to check when doing GC */
LIST_HEAD(Unit, gc_queue);
+ /* Units that should be realized */
+ LIST_HEAD(Unit, cgroup_queue);
+
Hashmap *watch_pids; /* pid => Unit object n:1 */
char *notify_socket;
@@ -139,7 +144,6 @@ struct Manager {
Set *unit_path_cache;
char **environment;
- char **default_controllers;
usec_t runtime_watchdog;
usec_t shutdown_watchdog;
@@ -198,7 +202,8 @@ struct Manager {
int dev_autofs_fd;
/* Data specific to the cgroup subsystem */
- Hashmap *cgroup_bondings; /* path string => CGroupBonding object 1:n */
+ Hashmap *cgroup_unit;
+ CGroupControllerMask cgroup_supported;
char *cgroup_root;
usec_t gc_queue_timestamp;
@@ -273,7 +278,6 @@ unsigned manager_dispatch_run_queue(Manager *m);
unsigned manager_dispatch_dbus_queue(Manager *m);
int manager_set_default_environment(Manager *m, char **environment);
-int manager_set_default_controllers(Manager *m, char **controllers);
int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit);
int manager_loop(Manager *m);
diff --git a/src/core/mount.c b/src/core/mount.c
index e21e774d4d..c71d51bfa4 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -82,6 +82,7 @@ static void mount_init(Unit *u) {
}
kill_context_init(&m->kill_context);
+ cgroup_context_init(&m->cgroup_context);
/* We need to make sure that /bin/mount is always called in
* the same process group as us, so that the autofs kernel
@@ -127,6 +128,7 @@ static void mount_done(Unit *u) {
mount_parameters_done(&m->parameters_proc_self_mountinfo);
mount_parameters_done(&m->parameters_fragment);
+ cgroup_context_done(&m->cgroup_context);
exec_context_done(&m->exec_context, manager_is_reloading_or_reexecuting(u->manager));
exec_command_done_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
m->control_command = NULL;
@@ -651,10 +653,6 @@ static int mount_add_extras(Mount *m) {
if (r < 0)
return r;
- r = unit_add_default_cgroups(u);
- if (r < 0)
- return r;
-
r = mount_fix_timeouts(m);
if (r < 0)
return r;
@@ -848,28 +846,31 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
assert(c);
assert(_pid);
+ unit_realize_cgroup(UNIT(m));
+
r = unit_watch_timer(UNIT(m), CLOCK_MONOTONIC, true, m->timeout_usec, &m->timer_watch);
if (r < 0)
goto fail;
- if ((r = exec_spawn(c,
- NULL,
- &m->exec_context,
- NULL, 0,
- UNIT(m)->manager->environment,
- true,
- true,
- true,
- UNIT(m)->manager->confirm_spawn,
- UNIT(m)->cgroup_bondings,
- UNIT(m)->cgroup_attributes,
- NULL,
- UNIT(m)->id,
- NULL,
- &pid)) < 0)
+ r = exec_spawn(c,
+ NULL,
+ &m->exec_context,
+ NULL, 0,
+ UNIT(m)->manager->environment,
+ true,
+ true,
+ true,
+ UNIT(m)->manager->confirm_spawn,
+ UNIT(m)->cgroup_mask,
+ UNIT(m)->cgroup_path,
+ UNIT(m)->id,
+ NULL,
+ &pid);
+ if (r < 0)
goto fail;
- if ((r = unit_watch_pid(UNIT(m), pid)) < 0)
+ r = unit_watch_pid(UNIT(m), pid);
+ if (r < 0)
/* FIXME: we need to do something here */
goto fail;
@@ -1878,8 +1879,9 @@ const UnitVTable mount_vtable = {
"Mount\0"
"Install\0",
+ .private_section = "Mount",
.exec_context_offset = offsetof(Mount, exec_context),
- .exec_section = "Mount",
+ .cgroup_context_offset = offsetof(Mount, cgroup_context),
.no_alias = true,
.no_instances = true,
diff --git a/src/core/mount.h b/src/core/mount.h
index bcc10ee0d4..7cd4320d94 100644
--- a/src/core/mount.h
+++ b/src/core/mount.h
@@ -25,6 +25,8 @@ typedef struct Mount Mount;
#include "unit.h"
#include "kill.h"
+#include "execute.h"
+#include "cgroup.h"
typedef enum MountState {
MOUNT_DEAD,
@@ -95,8 +97,10 @@ struct Mount {
usec_t timeout_usec;
ExecCommand exec_command[_MOUNT_EXEC_COMMAND_MAX];
+
ExecContext exec_context;
KillContext kill_context;
+ CGroupContext cgroup_context;
MountState state, deserialized_state;
diff --git a/src/core/service.c b/src/core/service.c
index a0c648a85b..5fdbdb13a3 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -141,6 +141,7 @@ static void service_init(Unit *u) {
exec_context_init(&s->exec_context);
kill_context_init(&s->kill_context);
+ cgroup_context_init(&s->cgroup_context);
RATELIMIT_INIT(s->start_limit, 10*USEC_PER_SEC, 5);
@@ -283,6 +284,7 @@ static void service_done(Unit *u) {
free(s->status_text);
s->status_text = NULL;
+ cgroup_context_done(&s->cgroup_context);
exec_context_done(&s->exec_context, manager_is_reloading_or_reexecuting(u->manager));
exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX);
s->control_command = NULL;
@@ -1229,10 +1231,6 @@ static int service_load(Unit *u) {
if (r < 0)
return r;
- r = unit_add_default_cgroups(u);
- if (r < 0)
- return r;
-
#ifdef HAVE_SYSV_COMPAT
r = sysv_fix_order(s);
if (r < 0)
@@ -1457,7 +1455,7 @@ static int service_search_main_pid(Service *s) {
assert(s->main_pid <= 0);
- pid = cgroup_bonding_search_main_pid_list(UNIT(s)->cgroup_bondings);
+ pid = unit_search_main_pid(UNIT(s));
if (pid <= 0)
return -ENOENT;
@@ -1582,7 +1580,7 @@ static void service_set_state(Service *s, ServiceState state) {
/* For the inactive states unit_notify() will trim the cgroup,
* but for exit we have to do that ourselves... */
if (state == SERVICE_EXITED && UNIT(s)->manager->n_reloading <= 0)
- cgroup_bonding_trim_list(UNIT(s)->cgroup_bondings, true);
+ unit_destroy_cgroup(UNIT(s));
if (old_state != state)
log_debug_unit(UNIT(s)->id,
@@ -1751,11 +1749,14 @@ static int service_spawn(
unsigned n_fds = 0, n_env = 0;
_cleanup_strv_free_ char
**argv = NULL, **final_env = NULL, **our_env = NULL;
+ const char *path;
assert(s);
assert(c);
assert(_pid);
+ unit_realize_cgroup(UNIT(s));
+
if (pass_fds ||
s->exec_context.std_input == EXEC_INPUT_SOCKET ||
s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
@@ -1811,7 +1812,7 @@ static int service_spawn(
goto fail;
}
- if (s->meta.manager->running_as != SYSTEMD_SYSTEM)
+ if (UNIT(s)->manager->running_as != SYSTEMD_SYSTEM)
if (asprintf(our_env + n_env++, "MANAGERPID=%lu", (unsigned long) getpid()) < 0) {
r = -ENOMEM;
goto fail;
@@ -1823,6 +1824,12 @@ static int service_spawn(
goto fail;
}
+ if (is_control && UNIT(s)->cgroup_path) {
+ path = strappenda(UNIT(s)->cgroup_path, "/control");
+ cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
+ } else
+ path = UNIT(s)->cgroup_path;
+
r = exec_spawn(c,
argv,
&s->exec_context,
@@ -1832,9 +1839,8 @@ static int service_spawn(
apply_chroot,
apply_tty_stdin,
UNIT(s)->manager->confirm_spawn,
- UNIT(s)->cgroup_bondings,
- UNIT(s)->cgroup_attributes,
- is_control ? "control" : NULL,
+ UNIT(s)->cgroup_mask,
+ path,
UNIT(s)->id,
s->type == SERVICE_IDLE ? UNIT(s)->manager->idle_pipe : NULL,
&pid);
@@ -1893,7 +1899,10 @@ static int cgroup_good(Service *s) {
assert(s);
- r = cgroup_bonding_is_empty_list(UNIT(s)->cgroup_bondings);
+ if (!UNIT(s)->cgroup_path)
+ return 0;
+
+ r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path, true);
if (r < 0)
return r;
@@ -2123,10 +2132,21 @@ fail:
service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
}
+static void service_kill_control_processes(Service *s) {
+ char *p;
+
+ if (!UNIT(s)->cgroup_path)
+ return;
+
+ p = strappenda(UNIT(s)->cgroup_path, "/control");
+
+ cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, p, SIGKILL, true, true, true, NULL);
+}
+
static void service_enter_start(Service *s) {
+ ExecCommand *c;
pid_t pid;
int r;
- ExecCommand *c;
assert(s);
@@ -2141,7 +2161,7 @@ static void service_enter_start(Service *s) {
/* We want to ensure that nobody leaks processes from
* START_PRE here, so let's go on a killing spree, People
* should not spawn long running processes from START_PRE. */
- cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, true, NULL, "control");
+ service_kill_control_processes(s);
if (s->type == SERVICE_FORKING) {
s->control_command_id = SERVICE_EXEC_START;
@@ -2217,11 +2237,9 @@ static void service_enter_start_pre(Service *s) {
s->control_command = s->exec_command[SERVICE_EXEC_START_PRE];
if (s->control_command) {
-
/* Before we start anything, let's clear up what might
* be left from previous runs. */
- cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL,
- true,true, NULL, "control");
+ service_kill_control_processes(s);
s->control_command_id = SERVICE_EXEC_START_PRE;
@@ -3045,7 +3063,6 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
}
} else if (s->control_pid == pid) {
-
s->control_pid = 0;
if (s->control_command) {
@@ -3066,8 +3083,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
/* Immediately get rid of the cgroup, so that the
* kernel doesn't delay the cgroup empty messages for
* the service cgroup any longer than necessary */
- cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL,
- true, true, NULL, "control");
+ service_kill_control_processes(s);
if (s->control_command &&
s->control_command->command_next &&
@@ -3296,7 +3312,7 @@ static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
}
}
-static void service_cgroup_notify_event(Unit *u) {
+static void service_notify_cgroup_empty_event(Unit *u) {
Service *s = SERVICE(u);
assert(u);
@@ -3823,8 +3839,9 @@ const UnitVTable service_vtable = {
"Service\0"
"Install\0",
+ .private_section = "Service",
.exec_context_offset = offsetof(Service, exec_context),
- .exec_section = "Service",
+ .cgroup_context_offset = offsetof(Service, cgroup_context),
.init = service_init,
.done = service_done,
@@ -3857,7 +3874,7 @@ const UnitVTable service_vtable = {
.reset_failed = service_reset_failed,
- .cgroup_notify_empty = service_cgroup_notify_event,
+ .notify_cgroup_empty = service_notify_cgroup_empty_event,
.notify_message = service_notify_message,
.bus_name_owner_change = service_bus_name_owner_change,
diff --git a/src/core/service.h b/src/core/service.h
index 703d3faa45..182cba1333 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -135,6 +135,7 @@ struct Service {
ExecContext exec_context;
KillContext kill_context;
+ CGroupContext cgroup_context;
ServiceState state, deserialized_state;
diff --git a/src/core/slice.c b/src/core/slice.c
index c1c33fe5c6..df2d91e473 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -36,6 +36,23 @@ static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = {
[SLICE_ACTIVE] = UNIT_ACTIVE
};
+static void slice_init(Unit *u) {
+ Slice *s = SLICE(u);
+
+ assert(u);
+ assert(u->load_state == UNIT_STUB);
+
+ cgroup_context_init(&s->cgroup_context);
+}
+
+static void slice_done(Unit *u) {
+ Slice *s = SLICE(u);
+
+ assert(u);
+
+ cgroup_context_done(&s->cgroup_context);
+}
+
static void slice_set_state(Slice *t, SliceState state) {
SliceState old_state;
assert(t);
@@ -52,23 +69,25 @@ static void slice_set_state(Slice *t, SliceState state) {
unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
}
-static int slice_add_slice_link(Slice *s) {
+static int slice_add_parent_slice(Slice *s) {
char *a, *dash;
- int r;
Unit *parent;
+ int r;
assert(s);
- if (UNIT_DEREF(UNIT(s)->slice))
+ if (UNIT_ISSET(UNIT(s)->slice))
return 0;
- a = strdupa(UNIT(s)->id);
-
- dash = strrchr(a, '-');
- if (!dash)
+ if (unit_has_name(UNIT(s), SPECIAL_ROOT_SLICE))
return 0;
- strcpy(dash, ".slice");
+ a = strdupa(UNIT(s)->id);
+ dash = strrchr(a, '-');
+ if (dash)
+ strcpy(dash, ".slice");
+ else
+ a = (char*) SPECIAL_ROOT_SLICE;
r = manager_load_unit(UNIT(s)->manager, a, NULL, NULL, &parent);
if (r < 0)
@@ -102,14 +121,15 @@ static int slice_verify(Slice *s) {
a = strdupa(UNIT(s)->id);
dash = strrchr(a, '-');
- if (dash) {
+ if (dash)
strcpy(dash, ".slice");
+ else
+ a = (char*) SPECIAL_ROOT_SLICE;
- if (!unit_has_name(UNIT_DEREF(UNIT(s)->slice), a)) {
- log_error_unit(UNIT(s)->id,
- "%s located outside its parent slice. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
+ if (!unit_has_name(UNIT_DEREF(UNIT(s)->slice), a)) {
+ log_error_unit(UNIT(s)->id,
+ "%s located outside its parent slice. Refusing.", UNIT(s)->id);
+ return -EINVAL;
}
}
@@ -122,14 +142,14 @@ static int slice_load(Unit *u) {
assert(s);
- r = unit_load_fragment_and_dropin(u);
+ r = unit_load_fragment_and_dropin_optional(u);
if (r < 0)
return r;
/* This is a new unit? Then let's add in some extras */
if (u->load_state == UNIT_LOADED) {
- r = slice_add_slice_link(s);
+ r = slice_add_parent_slice(s);
if (r < 0)
return r;
@@ -138,10 +158,6 @@ static int slice_load(Unit *u) {
if (r < 0)
return r;
}
-
- r = unit_add_default_cgroups(UNIT(s));
- if (r < 0)
- return r;
}
return slice_verify(s);
@@ -168,20 +184,17 @@ static void slice_dump(Unit *u, FILE *f, const char *prefix) {
fprintf(f,
"%sSlice State: %s\n",
prefix, slice_state_to_string(t->state));
+
+ cgroup_context_dump(&t->cgroup_context, f, prefix);
}
static int slice_start(Unit *u) {
Slice *t = SLICE(u);
- int r;
assert(t);
assert(t->state == SLICE_DEAD);
- r = cgroup_bonding_realize_list(u->cgroup_bondings);
- if (r < 0)
- return r;
-
- cgroup_attribute_apply_list(u->cgroup_attributes, u->cgroup_bondings);
+ unit_realize_cgroup(u);
slice_set_state(t, SLICE_ACTIVE);
return 0;
@@ -193,8 +206,8 @@ static int slice_stop(Unit *u) {
assert(t);
assert(t->state == SLICE_ACTIVE);
- /* We do not need to trim the cgroup explicitly, unit_notify()
- * will do that for us anyway. */
+ /* We do not need to destroy the cgroup explicitly,
+ * unit_notify() will do that for us anyway. */
slice_set_state(t, SLICE_DEAD);
return 0;
@@ -264,10 +277,16 @@ const UnitVTable slice_vtable = {
"Slice\0"
"Install\0",
+ .private_section = "Slice",
+ .cgroup_context_offset = offsetof(Slice, cgroup_context),
+
.no_alias = true,
.no_instances = true,
+ .init = slice_init,
.load = slice_load,
+ .done = slice_done,
+
.coldplug = slice_coldplug,
.dump = slice_dump,
@@ -288,11 +307,11 @@ const UnitVTable slice_vtable = {
.status_message_formats = {
.finished_start_job = {
- [JOB_DONE] = "Installed slice %s.",
+ [JOB_DONE] = "Created slice %s.",
[JOB_DEPENDENCY] = "Dependency failed for %s.",
},
.finished_stop_job = {
- [JOB_DONE] = "Deinstalled slice %s.",
+ [JOB_DONE] = "Removed slice %s.",
},
},
};
diff --git a/src/core/slice.h b/src/core/slice.h
index 4320a6354b..ad0c63902b 100644
--- a/src/core/slice.h
+++ b/src/core/slice.h
@@ -36,6 +36,8 @@ struct Slice {
Unit meta;
SliceState state, deserialized_state;
+
+ CGroupContext cgroup_context;
};
extern const UnitVTable slice_vtable;
diff --git a/src/core/socket.c b/src/core/socket.c
index 2f25e25aa6..c1bbaec447 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -88,6 +88,7 @@ static void socket_init(Unit *u) {
s->exec_context.std_output = u->manager->default_std_output;
s->exec_context.std_error = u->manager->default_std_error;
kill_context_init(&s->kill_context);
+ cgroup_context_init(&s->cgroup_context);
s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
}
@@ -128,6 +129,8 @@ static void socket_done(Unit *u) {
socket_free_ports(s);
exec_context_done(&s->exec_context, manager_is_reloading_or_reexecuting(u->manager));
+ cgroup_context_init(&s->cgroup_context);
+
exec_command_free_array(s->exec_command, _SOCKET_EXEC_COMMAND_MAX);
s->control_command = NULL;
@@ -399,10 +402,6 @@ static int socket_load(Unit *u) {
if (r < 0)
return r;
- r = unit_add_default_cgroups(u);
- if (r < 0)
- return r;
-
if (UNIT(s)->default_dependencies)
if ((r = socket_add_default_dependencies(s)) < 0)
return r;
@@ -1210,6 +1209,8 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
assert(c);
assert(_pid);
+ unit_realize_cgroup(UNIT(s));
+
r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_usec, &s->timer_watch);
if (r < 0)
goto fail;
@@ -1229,9 +1230,8 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
true,
true,
UNIT(s)->manager->confirm_spawn,
- UNIT(s)->cgroup_bondings,
- UNIT(s)->cgroup_attributes,
- NULL,
+ UNIT(s)->cgroup_mask,
+ UNIT(s)->cgroup_path,
UNIT(s)->id,
NULL,
&pid);
@@ -2361,8 +2361,9 @@ const UnitVTable socket_vtable = {
"Socket\0"
"Install\0",
+ .private_section = "Socket",
.exec_context_offset = offsetof(Socket, exec_context),
- .exec_section = "Socket",
+ .cgroup_context_offset = offsetof(Socket, cgroup_context),
.init = socket_init,
.done = socket_done,
diff --git a/src/core/socket.h b/src/core/socket.h
index 9d48cde0a6..15942c1c90 100644
--- a/src/core/socket.h
+++ b/src/core/socket.h
@@ -102,6 +102,7 @@ struct Socket {
ExecCommand* exec_command[_SOCKET_EXEC_COMMAND_MAX];
ExecContext exec_context;
KillContext kill_context;
+ CGroupContext cgroup_context;
/* For Accept=no sockets refers to the one service we'll
activate. For Accept=yes sockets is either NULL, or filled
diff --git a/src/core/special.h b/src/core/special.h
index 337a0a43e9..6d252e7baa 100644
--- a/src/core/special.h
+++ b/src/core/special.h
@@ -118,3 +118,4 @@
#define SPECIAL_SYSTEM_SLICE "system.slice"
#define SPECIAL_USER_SLICE "user.slice"
#define SPECIAL_MACHINE_SLICE "machine.slice"
+#define SPECIAL_ROOT_SLICE "-.slice"
diff --git a/src/core/swap.c b/src/core/swap.c
index d6721a6b31..0d4b4fa4f9 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -92,6 +92,7 @@ static void swap_init(Unit *u) {
s->exec_context.std_output = u->manager->default_std_output;
s->exec_context.std_error = u->manager->default_std_error;
kill_context_init(&s->kill_context);
+ cgroup_context_init(&s->cgroup_context);
s->parameters_proc_swaps.priority = s->parameters_fragment.priority = -1;
@@ -129,6 +130,8 @@ static void swap_done(Unit *u) {
exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
s->control_command = NULL;
+ cgroup_context_done(&s->cgroup_context);
+
swap_unwatch_control_pid(s);
unit_unwatch_timer(u, &s->timer_watch);
@@ -291,10 +294,6 @@ static int swap_load(Unit *u) {
if (r < 0)
return r;
- r = unit_add_default_cgroups(u);
- if (r < 0)
- return r;
-
if (UNIT(s)->default_dependencies) {
r = swap_add_default_dependencies(s);
if (r < 0)
@@ -593,6 +592,8 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
assert(c);
assert(_pid);
+ unit_realize_cgroup(UNIT(s));
+
r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_usec, &s->timer_watch);
if (r < 0)
goto fail;
@@ -606,9 +607,8 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
true,
true,
UNIT(s)->manager->confirm_spawn,
- UNIT(s)->cgroup_bondings,
- UNIT(s)->cgroup_attributes,
- NULL,
+ UNIT(s)->cgroup_mask,
+ UNIT(s)->cgroup_path,
UNIT(s)->id,
NULL,
&pid);
@@ -1327,8 +1327,9 @@ const UnitVTable swap_vtable = {
"Swap\0"
"Install\0",
+ .private_section = "Swap",
.exec_context_offset = offsetof(Swap, exec_context),
- .exec_section = "Swap",
+ .cgroup_context_offset = offsetof(Swap, cgroup_context),
.no_alias = true,
.no_instances = true,
diff --git a/src/core/swap.h b/src/core/swap.h
index 121889d1d5..7e48c0ea3b 100644
--- a/src/core/swap.h
+++ b/src/core/swap.h
@@ -88,6 +88,7 @@ struct Swap {
ExecCommand exec_command[_SWAP_EXEC_COMMAND_MAX];
ExecContext exec_context;
KillContext kill_context;
+ CGroupContext cgroup_context;
SwapState state, deserialized_state;
diff --git a/src/core/unit.c b/src/core/unit.c
index f75045dc48..0dcf85b5e0 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -44,7 +44,6 @@
#include "special.h"
#include "cgroup-util.h"
#include "missing.h"
-#include "cgroup-attr.h"
#include "mkdir.h"
#include "label.h"
#include "fileio-label.h"
@@ -402,9 +401,10 @@ void unit_free(Unit *u) {
u->manager->n_in_gc_queue--;
}
- cgroup_bonding_free_list(u->cgroup_bondings, u->manager->n_reloading <= 0);
- cgroup_attribute_free_list(u->cgroup_attributes);
+ if (u->in_cgroup_queue)
+ LIST_REMOVE(Unit, cgroup_queue, u->manager->cgroup_queue, u);
+ free(u->cgroup_path);
free(u->description);
strv_free(u->documentation);
free(u->fragment_path);
@@ -673,7 +673,10 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
"%s\tInactive Enter Timestamp: %s\n"
"%s\tGC Check Good: %s\n"
"%s\tNeed Daemon Reload: %s\n"
- "%s\tSlice: %s\n",
+ "%s\tSlice: %s\n"
+ "%s\tCGroup: %s\n"
+ "%s\tCGroup realized: %s\n"
+ "%s\tCGroup mask: 0x%x\n",
prefix, u->id,
prefix, unit_description(u),
prefix, strna(u->instance),
@@ -685,7 +688,10 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
prefix, strna(format_timestamp(timestamp4, sizeof(timestamp4), u->inactive_enter_timestamp.realtime)),
prefix, yes_no(unit_check_gc(u)),
prefix, yes_no(unit_need_daemon_reload(u)),
- prefix, strna(unit_slice_name(u)));
+ prefix, strna(unit_slice_name(u)),
+ prefix, strna(u->cgroup_path),
+ prefix, yes_no(u->cgroup_realized),
+ prefix, u->cgroup_mask);
SET_FOREACH(t, u->names, i)
fprintf(f, "%s\tName: %s\n", prefix, t);
@@ -735,8 +741,6 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
}
if (u->load_state == UNIT_LOADED) {
- CGroupBonding *b;
- CGroupAttribute *a;
fprintf(f,
"%s\tStopWhenUnneeded: %s\n"
@@ -754,20 +758,6 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
prefix, yes_no(u->ignore_on_isolate),
prefix, yes_no(u->ignore_on_snapshot));
- LIST_FOREACH(by_unit, b, u->cgroup_bondings)
- fprintf(f, "%s\tControlGroup: %s:%s\n",
- prefix, b->controller, b->path);
-
- LIST_FOREACH(by_unit, a, u->cgroup_attributes) {
- _cleanup_free_ char *v = NULL;
-
- if (a->semantics && a->semantics->map_write)
- a->semantics->map_write(a->semantics, a->value, &v);
-
- fprintf(f, "%s\tControlGroupAttribute: %s %s \"%s\"\n",
- prefix, a->controller, a->name, v ? v : a->value);
- }
-
if (UNIT_VTABLE(u)->dump)
UNIT_VTABLE(u)->dump(u, f, prefix2);
@@ -795,14 +785,16 @@ int unit_load_fragment_and_dropin(Unit *u) {
assert(u);
/* Load a .service file */
- if ((r = unit_load_fragment(u)) < 0)
+ r = unit_load_fragment(u);
+ if (r < 0)
return r;
if (u->load_state == UNIT_STUB)
return -ENOENT;
/* Load drop-in directory data */
- if ((r = unit_load_dropin(unit_follow_merge(u))) < 0)
+ r = unit_load_dropin(unit_follow_merge(u));
+ if (r < 0)
return r;
return 0;
@@ -818,14 +810,16 @@ int unit_load_fragment_and_dropin_optional(Unit *u) {
* something can be loaded or not doesn't matter. */
/* Load a .service file */
- if ((r = unit_load_fragment(u)) < 0)
+ r = unit_load_fragment(u);
+ if (r < 0)
return r;
if (u->load_state == UNIT_STUB)
u->load_state = UNIT_LOADED;
/* Load drop-in directory data */
- if ((r = unit_load_dropin(unit_follow_merge(u))) < 0)
+ r = unit_load_dropin(unit_follow_merge(u));
+ if (r < 0)
return r;
return 0;
@@ -880,8 +874,12 @@ static int unit_add_default_dependencies(Unit *u) {
return r;
}
- if (u->default_dependencies && UNIT_ISSET(u->slice)) {
- r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, UNIT_DEREF(u->slice), true);
+ if (u->default_dependencies && unit_get_cgroup_context(u)) {
+ if (UNIT_ISSET(u->slice))
+ r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, UNIT_DEREF(u->slice), true);
+ else
+ r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, SPECIAL_ROOT_SLICE, NULL, true);
+
if (r < 0)
return r;
}
@@ -1382,7 +1380,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
}
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- cgroup_bonding_trim_list(u->cgroup_bondings, true);
+ unit_destroy_cgroup(u);
if (UNIT_IS_INACTIVE_OR_FAILED(os) != UNIT_IS_INACTIVE_OR_FAILED(ns)) {
ExecContext *ec = unit_get_exec_context(u);
@@ -1952,51 +1950,16 @@ char *unit_dbus_path(Unit *u) {
return unit_dbus_path_from_name(u->id);
}
-static int unit_add_cgroup(Unit *u, CGroupBonding *b) {
- int r;
-
- assert(u);
- assert(b);
-
- assert(b->path);
-
- if (!b->controller) {
- b->controller = strdup(SYSTEMD_CGROUP_CONTROLLER);
- if (!b->controller)
- return log_oom();
-
- b->ours = true;
- }
-
- /* Ensure this hasn't been added yet */
- assert(!b->unit);
-
- if (streq(b->controller, SYSTEMD_CGROUP_CONTROLLER)) {
- CGroupBonding *l;
-
- l = hashmap_get(u->manager->cgroup_bondings, b->path);
- LIST_PREPEND(CGroupBonding, by_path, l, b);
-
- r = hashmap_replace(u->manager->cgroup_bondings, b->path, l);
- if (r < 0) {
- LIST_REMOVE(CGroupBonding, by_path, l, b);
- return r;
- }
- }
-
- LIST_PREPEND(CGroupBonding, by_unit, u->cgroup_bondings, b);
- b->unit = u;
-
- return 0;
-}
-
char *unit_default_cgroup_path(Unit *u) {
_cleanup_free_ char *escaped_instance = NULL, *slice = NULL;
int r;
assert(u);
- if (UNIT_ISSET(u->slice)) {
+ if (unit_has_name(u, SPECIAL_ROOT_SLICE))
+ return strdup(u->manager->cgroup_root);
+
+ if (UNIT_ISSET(u->slice) && !unit_has_name(UNIT_DEREF(u->slice), SPECIAL_ROOT_SLICE)) {
r = cg_slice_to_path(UNIT_DEREF(u->slice)->id, &slice);
if (r < 0)
return NULL;
@@ -2026,148 +1989,6 @@ char *unit_default_cgroup_path(Unit *u) {
escaped_instance, NULL);
}
-int unit_add_cgroup_from_text(Unit *u, const char *name, bool overwrite, CGroupBonding **ret) {
- char *controller = NULL, *path = NULL;
- CGroupBonding *b = NULL;
- bool ours = false;
- int r;
-
- assert(u);
- assert(name);
-
- r = cg_split_spec(name, &controller, &path);
- if (r < 0)
- return r;
-
- if (!path) {
- path = unit_default_cgroup_path(u);
- ours = true;
- }
-
- if (!controller) {
- controller = strdup("systemd");
- ours = true;
- }
-
- if (!path || !controller) {
- free(path);
- free(controller);
- return log_oom();
- }
-
- if (streq(controller, "systemd")) {
- /* Within the systemd unit hierarchy we do not allow changes. */
- if (path_startswith(path, "/system")) {
- log_warning_unit(u->id, "Manipulating the systemd:/system cgroup hierarchy is not permitted.");
- free(path);
- free(controller);
- return -EPERM;
- }
- }
-
- b = cgroup_bonding_find_list(u->cgroup_bondings, controller);
- if (b) {
- if (streq(path, b->path)) {
- free(path);
- free(controller);
-
- if (ret)
- *ret = b;
- return 0;
- }
-
- if (overwrite && !b->essential) {
- free(controller);
-
- free(b->path);
- b->path = path;
-
- b->ours = ours;
- b->realized = false;
-
- if (ret)
- *ret = b;
-
- return 1;
- }
-
- r = -EEXIST;
- b = NULL;
- goto fail;
- }
-
- b = new0(CGroupBonding, 1);
- if (!b) {
- r = -ENOMEM;
- goto fail;
- }
-
- b->controller = controller;
- b->path = path;
- b->ours = ours;
- b->essential = streq(controller, SYSTEMD_CGROUP_CONTROLLER);
-
- r = unit_add_cgroup(u, b);
- if (r < 0)
- goto fail;
-
- if (ret)
- *ret = b;
-
- return 1;
-
-fail:
- free(path);
- free(controller);
- free(b);
-
- return r;
-}
-
-static int unit_add_one_default_cgroup(Unit *u, const char *controller) {
- CGroupBonding *b = NULL;
- int r = -ENOMEM;
-
- assert(u);
-
- if (controller && !cg_controller_is_valid(controller, true))
- return -EINVAL;
-
- if (!controller)
- controller = SYSTEMD_CGROUP_CONTROLLER;
-
- if (cgroup_bonding_find_list(u->cgroup_bondings, controller))
- return 0;
-
- b = new0(CGroupBonding, 1);
- if (!b)
- return -ENOMEM;
-
- b->controller = strdup(controller);
- if (!b->controller)
- goto fail;
-
- b->path = unit_default_cgroup_path(u);
- if (!b->path)
- goto fail;
-
- b->ours = true;
- b->essential = streq(controller, SYSTEMD_CGROUP_CONTROLLER);
-
- r = unit_add_cgroup(u, b);
- if (r < 0)
- goto fail;
-
- return 1;
-
-fail:
- free(b->path);
- free(b->controller);
- free(b);
-
- return r;
-}
-
int unit_add_default_slice(Unit *u) {
Unit *slice;
int r;
@@ -2177,10 +1998,10 @@ int unit_add_default_slice(Unit *u) {
if (UNIT_ISSET(u->slice))
return 0;
- if (u->manager->running_as != SYSTEMD_SYSTEM)
+ if (!unit_get_cgroup_context(u))
return 0;
- r = manager_load_unit(u->manager, SPECIAL_SYSTEM_SLICE, NULL, NULL, &slice);
+ r = manager_load_unit(u->manager, u->manager->running_as == SYSTEMD_SYSTEM ? SPECIAL_SYSTEM_SLICE : SPECIAL_ROOT_SLICE, NULL, NULL, &slice);
if (r < 0)
return r;
@@ -2197,148 +2018,6 @@ const char *unit_slice_name(Unit *u) {
return UNIT_DEREF(u->slice)->id;
}
-int unit_add_default_cgroups(Unit *u) {
- CGroupAttribute *a;
- char **c;
- int r;
-
- assert(u);
-
- /* Adds in the default cgroups, if they weren't specified
- * otherwise. */
-
- if (!u->manager->cgroup_root)
- return 0;
-
- r = unit_add_one_default_cgroup(u, NULL);
- if (r < 0)
- return r;
-
- STRV_FOREACH(c, u->manager->default_controllers)
- unit_add_one_default_cgroup(u, *c);
-
- LIST_FOREACH(by_unit, a, u->cgroup_attributes)
- unit_add_one_default_cgroup(u, a->controller);
-
- return 0;
-}
-
-CGroupBonding* unit_get_default_cgroup(Unit *u) {
- assert(u);
-
- return cgroup_bonding_find_list(u->cgroup_bondings, NULL);
-}
-
-int unit_add_cgroup_attribute(
- Unit *u,
- const CGroupSemantics *semantics,
- const char *controller,
- const char *name,
- const char *value,
- CGroupAttribute **ret) {
-
- _cleanup_free_ char *c = NULL;
- CGroupAttribute *a;
- int r;
-
- assert(u);
- assert(value);
-
- if (semantics) {
- /* Semantics always take precedence */
- if (semantics->name)
- name = semantics->name;
-
- if (semantics->controller)
- controller = semantics->controller;
- }
-
- if (!name)
- return -EINVAL;
-
- if (!controller) {
- r = cg_controller_from_attr(name, &c);
- if (r < 0)
- return -EINVAL;
-
- controller = c;
- }
-
- if (!controller ||
- streq(controller, SYSTEMD_CGROUP_CONTROLLER) ||
- streq(controller, "systemd"))
- return -EINVAL;
-
- if (!filename_is_safe(name))
- return -EINVAL;
-
- if (!cg_controller_is_valid(controller, false))
- return -EINVAL;
-
- /* Check if this attribute already exists. Note that we will
- * explicitly check for the value here too, as there are
- * attributes which accept multiple values. */
- a = cgroup_attribute_find_list(u->cgroup_attributes, controller, name);
- if (a) {
- if (streq(value, a->value)) {
- /* Exactly the same value is always OK, let's ignore this */
- if (ret)
- *ret = a;
-
- return 0;
- }
-
- if (semantics && !semantics->multiple) {
- char *v;
-
- /* If this is a single-item entry, we can
- * simply patch the existing attribute */
-
- v = strdup(value);
- if (!v)
- return -ENOMEM;
-
- free(a->value);
- a->value = v;
-
- if (ret)
- *ret = a;
- return 1;
- }
- }
-
- a = new0(CGroupAttribute, 1);
- if (!a)
- return -ENOMEM;
-
- if (c) {
- a->controller = c;
- c = NULL;
- } else
- a->controller = strdup(controller);
-
- a->name = strdup(name);
- a->value = strdup(value);
-
- if (!a->controller || !a->name || !a->value) {
- free(a->controller);
- free(a->name);
- free(a->value);
- free(a);
- return -ENOMEM;
- }
-
- a->semantics = semantics;
- a->unit = u;
-
- LIST_PREPEND(CGroupAttribute, by_unit, u->cgroup_attributes, a);
-
- if (ret)
- *ret = a;
-
- return 1;
-}
-
int unit_load_related_unit(Unit *u, const char *type, Unit **_found) {
_cleanup_free_ char *t = NULL;
int r;
@@ -2804,7 +2483,7 @@ int unit_kill_common(
if (kill(main_pid, signo) < 0)
r = -errno;
- if (who == KILL_ALL) {
+ if (who == KILL_ALL && u->cgroup_path) {
_cleanup_set_free_ Set *pid_set = NULL;
int q;
@@ -2825,7 +2504,7 @@ int unit_kill_common(
return q;
}
- q = cgroup_bonding_kill_list(u->cgroup_bondings, signo, false, false, pid_set, NULL);
+ q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set);
if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
r = q;
}
@@ -2924,7 +2603,6 @@ int unit_exec_context_defaults(Unit *u, ExecContext *c) {
assert(c);
/* This only copies in the ones that need memory */
-
for (i = 0; i < RLIMIT_NLIMITS; i++)
if (u->manager->rlimit[i] && !c->rlimit[i]) {
c->rlimit[i] = newdup(struct rlimit, u->manager->rlimit[i], 1);
@@ -2954,6 +2632,16 @@ ExecContext *unit_get_exec_context(Unit *u) {
return (ExecContext*) ((uint8_t*) u + offset);
}
+CGroupContext *unit_get_cgroup_context(Unit *u) {
+ size_t offset;
+
+ offset = UNIT_VTABLE(u)->cgroup_context_offset;
+ if (offset <= 0)
+ return NULL;
+
+ return (CGroupContext*) ((uint8_t*) u + offset);
+}
+
static int drop_in_file(Unit *u, bool runtime, const char *name, char **_p, char **_q) {
char *p, *q;
int r;
@@ -3072,7 +2760,7 @@ int unit_kill_context(
wait_for_exit = true;
}
- if (c->kill_mode == KILL_CONTROL_GROUP) {
+ if (c->kill_mode == KILL_CONTROL_GROUP && u->cgroup_path) {
_cleanup_set_free_ Set *pid_set = NULL;
pid_set = set_new(trivial_hash_func, trivial_compare_func);
@@ -3092,7 +2780,7 @@ int unit_kill_context(
return r;
}
- r = cgroup_bonding_kill_list(u->cgroup_bondings, sig, true, false, pid_set, NULL);
+ r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, sig, true, true, false, pid_set);
if (r < 0) {
if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
log_warning_unit(u->id, "Failed to kill control group: %s", strerror(-r));
diff --git a/src/core/unit.h b/src/core/unit.h
index da52101bd2..fbcaabe167 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -37,10 +37,10 @@ typedef struct UnitStatusMessageFormats UnitStatusMessageFormats;
#include "list.h"
#include "socket-util.h"
#include "execute.h"
+#include "cgroup.h"
#include "condition.h"
#include "install.h"
#include "unit-name.h"
-#include "cgroup-semantics.h"
enum UnitActiveState {
UNIT_ACTIVE,
@@ -115,8 +115,6 @@ enum UnitDependency {
#include "manager.h"
#include "job.h"
-#include "cgroup.h"
-#include "cgroup-attr.h"
struct UnitRef {
/* Keeps tracks of references to a unit. This is useful so
@@ -174,8 +172,9 @@ struct Unit {
dual_timestamp inactive_enter_timestamp;
/* Counterparts in the cgroup filesystem */
- CGroupBonding *cgroup_bondings;
- CGroupAttribute *cgroup_attributes;
+ char *cgroup_path;
+ bool cgroup_realized;
+ CGroupControllerMask cgroup_mask;
UnitRef slice;
@@ -197,6 +196,9 @@ struct Unit {
/* GC queue */
LIST_FIELDS(Unit, gc_queue);
+ /* CGroup realize members queue */
+ LIST_FIELDS(Unit, cgroup_queue);
+
/* Used during GC sweeps */
unsigned gc_marker;
@@ -243,6 +245,7 @@ struct Unit {
bool in_dbus_queue:1;
bool in_cleanup_queue:1;
bool in_gc_queue:1;
+ bool in_cgroup_queue:1;
bool sent_dbus_new_signal:1;
@@ -277,8 +280,12 @@ struct UnitVTable {
* ExecContext is found, if the unit type has that */
size_t exec_context_offset;
- /* The name of the section with the exec settings of ExecContext */
- const char *exec_section;
+ /* If greater than 0, the offset into the object where
+ * CGroupContext is found, if the unit type has that */
+ size_t cgroup_context_offset;
+
+ /* The name of the configuration file section with the private settings of this unit*/
+ const char *private_section;
/* Config file sections this unit type understands, separated
* by NUL chars */
@@ -350,7 +357,7 @@ struct UnitVTable {
/* Called whenever any of the cgroups this unit watches for
* ran empty */
- void (*cgroup_notify_empty)(Unit *u);
+ void (*notify_cgroup_empty)(Unit *u);
/* Called whenever a process of this unit sends us a message */
void (*notify_message)(Unit *u, pid_t pid, char **tags);
@@ -454,11 +461,6 @@ int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDep
int unit_add_exec_dependencies(Unit *u, ExecContext *c);
-int unit_add_cgroup_from_text(Unit *u, const char *name, bool overwrite, CGroupBonding **ret);
-int unit_add_default_cgroups(Unit *u);
-CGroupBonding* unit_get_default_cgroup(Unit *u);
-int unit_add_cgroup_attribute(Unit *u, const CGroupSemantics *semantics, const char *controller, const char *name, const char *value, CGroupAttribute **ret);
-
int unit_choose_id(Unit *u, const char *name);
int unit_set_description(Unit *u, const char *description);
@@ -573,6 +575,7 @@ int unit_add_mount_links(Unit *u);
int unit_exec_context_defaults(Unit *u, ExecContext *c);
ExecContext *unit_get_exec_context(Unit *u) _pure_;
+CGroupContext *unit_get_cgroup_context(Unit *u) _pure_;
int unit_write_drop_in(Unit *u, bool runtime, const char *name, const char *data);
int unit_remove_drop_in(Unit *u, bool runtime, const char *name);