chiark / gitweb /
core: general cgroup rework
authorLennart Poettering <lennart@poettering.net>
Thu, 27 Jun 2013 02:14:27 +0000 (04:14 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 27 Jun 2013 02:17:34 +0000 (04:17 +0200)
Replace the very generic cgroup hookup with a much simpler one. With
this change only the high-level cgroup settings remain, the ability to
set arbitrary cgroup attributes is removed, so is support for adding
units to arbitrary cgroup controllers or setting arbitrary paths for
them (especially paths that are different for the various controllers).

This also introduces a new -.slice root slice, that is the parent of
system.slice and friends. This enables easy admin configuration of
root-level cgrouo properties.

This replaces DeviceDeny= by DevicePolicy=, and implicitly adds in
/dev/null, /dev/zero and friends if DeviceAllow= is used (unless this is
turned off by DevicePolicy=).

57 files changed:
Makefile.am
TODO
src/core/cgroup-attr.c [deleted file]
src/core/cgroup-attr.h [deleted file]
src/core/cgroup-semantics.c [deleted file]
src/core/cgroup-semantics.h [deleted file]
src/core/cgroup.c
src/core/cgroup.h
src/core/dbus-cgroup.c [new file with mode: 0644]
src/core/dbus-cgroup.h [new file with mode: 0644]
src/core/dbus-execute.c
src/core/dbus-execute.h
src/core/dbus-manager.c
src/core/dbus-mount.c
src/core/dbus-service.c
src/core/dbus-slice.c
src/core/dbus-socket.c
src/core/dbus-swap.c
src/core/dbus-unit.c
src/core/dbus-unit.h
src/core/dbus.c
src/core/execute.c
src/core/execute.h
src/core/load-fragment-gperf.gperf.m4
src/core/load-fragment.c
src/core/load-fragment.h
src/core/main.c
src/core/manager.c
src/core/manager.h
src/core/mount.c
src/core/mount.h
src/core/service.c
src/core/service.h
src/core/slice.c
src/core/slice.h
src/core/socket.c
src/core/socket.h
src/core/special.h
src/core/swap.c
src/core/swap.h
src/core/unit.c
src/core/unit.h
src/login/logind-machine.c
src/login/logind-session.c
src/login/logind-user.c
src/shared/cgroup-label.c
src/shared/cgroup-show.c
src/shared/cgroup-util.c
src/shared/cgroup-util.h
src/shared/fileio.c
src/shared/mkdir.c
src/shared/mkdir.h
src/systemctl/systemctl.c
src/test/test-cgroup.c
units/-.slice [new file with mode: 0644]
units/slices.target
units/system.slice

index 016d7dad3264dd226f12edf58785e3b07a21aa97..12254e39a8d64f30808ff7619f33685cba271e6e 100644 (file)
@@ -379,6 +379,7 @@ dist_systemunit_DATA = \
        units/swap.target \
        units/slices.target \
        units/system.slice \
        units/swap.target \
        units/slices.target \
        units/system.slice \
+       units/-.slice \
        units/systemd-initctl.socket \
        units/systemd-shutdownd.socket \
        units/syslog.socket \
        units/systemd-initctl.socket \
        units/systemd-shutdownd.socket \
        units/syslog.socket \
@@ -880,14 +881,16 @@ libsystemd_core_la_SOURCES = \
        src/core/dbus-snapshot.h \
        src/core/dbus-device.c \
        src/core/dbus-device.h \
        src/core/dbus-snapshot.h \
        src/core/dbus-device.c \
        src/core/dbus-device.h \
-       src/core/dbus-execute.c \
-       src/core/dbus-execute.h \
-       src/core/dbus-kill.c \
-       src/core/dbus-kill.h \
        src/core/dbus-path.c \
        src/core/dbus-path.h \
        src/core/dbus-slice.c \
        src/core/dbus-slice.h \
        src/core/dbus-path.c \
        src/core/dbus-path.h \
        src/core/dbus-slice.c \
        src/core/dbus-slice.h \
+       src/core/dbus-execute.c \
+       src/core/dbus-execute.h \
+       src/core/dbus-kill.c \
+       src/core/dbus-kill.h \
+       src/core/dbus-cgroup.c \
+       src/core/dbus-cgroup.h \
        src/core/cgroup.c \
        src/core/cgroup.h \
        src/core/selinux-access.c \
        src/core/cgroup.c \
        src/core/cgroup.h \
        src/core/selinux-access.c \
@@ -914,10 +917,6 @@ libsystemd_core_la_SOURCES = \
        src/core/namespace.h \
        src/core/tcpwrap.c \
        src/core/tcpwrap.h \
        src/core/namespace.h \
        src/core/tcpwrap.c \
        src/core/tcpwrap.h \
-       src/core/cgroup-attr.c \
-       src/core/cgroup-attr.h \
-       src/core/cgroup-semantics.c \
-       src/core/cgroup-semantics.h \
        src/core/securebits.h \
        src/core/initreq.h \
        src/core/special.h \
        src/core/securebits.h \
        src/core/initreq.h \
        src/core/special.h \
@@ -1137,6 +1136,10 @@ test_ns_SOURCES = \
 test_ns_LDADD = \
        libsystemd-core.la
 
 test_ns_LDADD = \
        libsystemd-core.la
 
+test_ns_CFLAGS = \
+       $(AM_CFLAGS) \
+       $(DBUS_CFLAGS)
+
 test_loopback_SOURCES = \
        src/test/test-loopback.c
 
 test_loopback_SOURCES = \
        src/test/test-loopback.c
 
diff --git a/TODO b/TODO
index caba4e39eb5ca8949be6ba6b43777637d13bd632..a61fa92b68ca591f1df86b9b768c3132d58f1fd2 100644 (file)
--- a/TODO
+++ b/TODO
@@ -28,11 +28,17 @@ Fedora 19:
 
 Features:
 
 
 Features:
 
-* journald: make sure ratelimit is actually really per-service with the new cgroup changes
+* split out CreateMachine into systemd-machined
+
+* "transient" units, i.e units that are not sourced from disk but
+  created only transiently via bus calls
 
 
-* when creating a session or machine, automatically move the process into the root cgroup for all other hierarchies
+* introduce new Scope unit type then make logind's session and machine
+  registration use this to set up cgroups
 
 
-* maybe reintroduce nspawn -C?
+* should Slice= be part of [Unit] or of [Service]?
+
+* journald: make sure ratelimit is actually really per-service with the new cgroup changes
 
 * move systemctl dump to systemd-analyze
 
 
 * move systemctl dump to systemd-analyze
 
@@ -49,12 +55,6 @@ Features:
 * when a service changes state make reflect that in the
   RUNNING/LISTENING states of its socket
 
 * when a service changes state make reflect that in the
   RUNNING/LISTENING states of its socket
 
-* slices:
-  - add option to pam_systemd to move login session into a slice (?)
-  - remove ControlGroup= setting
-  - in sd_pid_get_owner_uid() fallback to query session file
-  - add api to determine slice of unit
-
 * when recursively showing the cgroup hierarchy, optionally also show
   the hierarchies of child processes
 
 * when recursively showing the cgroup hierarchy, optionally also show
   the hierarchies of child processes
 
diff --git a/src/core/cgroup-attr.c b/src/core/cgroup-attr.c
deleted file mode 100644 (file)
index 7e3e08e..0000000
+++ /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 (file)
index 3a13b7c..0000000
+++ /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 (file)
index 7df9d01..0000000
+++ /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 (file)
index 4f848f4..0000000
+++ /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);
index 5065329739d96fae779c0577ced5f145b075c8bd..79467a82cea8ea4ac0c3a659017488067dded84f 100644 (file)
@@ -3,7 +3,7 @@
 /***
   This file is part of systemd.
 
 /***
   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
 
   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
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
   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 <fcntl.h>
 
-#include "cgroup.h"
-#include "cgroup-util.h"
-#include "log.h"
-#include "strv.h"
 #include "path-util.h"
 #include "special.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);
-        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) {
         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;
 }
 
 
         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;
 
         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;
 
                         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)
                 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;
 }
 
         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;
 
                                 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;
 
         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) {
 }
 
 int manager_setup_cgroup(Manager *m) {
@@ -394,8 +643,8 @@ int manager_setup_cgroup(Manager *m) {
                 return -errno;
         }
 
                 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;
 }
 
         return 0;
 }
@@ -417,201 +666,71 @@ void manager_shutdown_cgroup(Manager *m, bool delete) {
         m->cgroup_root = NULL;
 }
 
         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;
         char *p;
+        Unit *u;
 
         assert(m);
         assert(cgroup);
 
         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);
 
         p = strdupa(cgroup);
-        if (!p)
-                return -ENOMEM;
-
         for (;;) {
                 char *e;
 
                 e = strrchr(p, '/');
         for (;;) {
                 char *e;
 
                 e = strrchr(p, '/');
-                if (e == p || !e) {
-                        *bonding = NULL;
-                        return 0;
-                }
+                if (e == p || !e)
+                        return NULL;
 
                 *e = 0;
 
 
                 *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;
 
         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;
 
         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 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;
 
                 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);
index 6555d89e37fe64430059598f2273f10aa577f8e2..96f1d9f7b6217a1601a29996884b14ff98a22145 100644 (file)
@@ -5,7 +5,7 @@
 /***
   This file is part of systemd.
 
 /***
   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
 
   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
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
   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 (file)
index 0000000..08ee9c8
--- /dev/null
@@ -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 (file)
index 0000000..a0a7a77
--- /dev/null
@@ -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[];
index 2a8a0e1ac58610a31564959b21a8ee4756fae3ec..73590c82be3db91ffca8d7ff8799afe6d9992e89 100644 (file)
 #include "syscall-list.h"
 #include "fileio.h"
 
 #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;
 
         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;
 }
 
         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;
 
         ExecContext *c = data;
         int32_t n;
 
@@ -92,7 +92,7 @@ int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property
         return 0;
 }
 
         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;
 
         ExecContext *c = data;
         int32_t n;
 
@@ -111,7 +111,7 @@ int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data
         return 0;
 }
 
         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;
 
         ExecContext *c = data;
         int32_t n;
 
@@ -130,7 +130,7 @@ int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *da
         return 0;
 }
 
         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;
 
         ExecContext *c = data;
         int32_t n;
 
@@ -149,7 +149,7 @@ int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property
         return 0;
 }
 
         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;
 
         ExecContext *c = data;
         int32_t n;
 
@@ -174,7 +174,7 @@ int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *proper
         return 0;
 }
 
         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;
         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;
 }
 
         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;
 
         ExecContext *c = data;
         uint64_t u;
 
@@ -219,7 +219,7 @@ int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property
         return 0;
 }
 
         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;
 
         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);
 }
 
         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;
         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;
 }
 
         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;
         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;
 }
 
         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;
         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 },
         { "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                                                   },
         { "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, }
+        {}
 };
 };
index 91d70e535fd1f525117f37ea2ad134cba3362939..5a6a559c9971f6171a38ef9d1320ddba97f3c716 100644 (file)
@@ -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=\"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"
         "  <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 }
 
 #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_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);
index d41b6ae15ff4955c1868918c039b8f96c946556f..c081ff5d1666b4ccbda841727afa6e86ed61fc87 100644 (file)
@@ -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 },
         { "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 },
         { "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);
 
                                     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);
                 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;
 
                 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;
         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
                 DBusMessageIter iter, sub;
                 Iterator i;
index 0fcceb500d068565835adda04fa381a341ee5c5d..16b7afe8b7e46847d83b029b56190d8fbf990ae9 100644 (file)
 #include <errno.h>
 
 #include "dbus-unit.h"
 #include <errno.h>
 
 #include "dbus-unit.h"
-#include "dbus-mount.h"
-#include "dbus-kill.h"
 #include "dbus-execute.h"
 #include "dbus-execute.h"
+#include "dbus-kill.h"
+#include "dbus-cgroup.h"
 #include "dbus-common.h"
 #include "selinux-access.h"
 #include "dbus-common.h"
 #include "selinux-access.h"
+#include "dbus-mount.h"
 
 #define BUS_MOUNT_INTERFACE                                             \
         " <interface name=\"org.freedesktop.systemd1.Mount\">\n"        \
 
 #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_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"    \
         "  <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[] = {
         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, }
         };
 
                 { NULL, }
         };
 
index 98bcdcb4020728254b6161fa632c189fabd4cc70..bbac1b816742e7d5577d9c55fbb58d32e8f62b21 100644 (file)
 #include "dbus-unit.h"
 #include "dbus-execute.h"
 #include "dbus-kill.h"
 #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-common.h"
 #include "selinux-access.h"
+#include "dbus-service.h"
 
 #define BUS_SERVICE_INTERFACE                                           \
         " <interface name=\"org.freedesktop.systemd1.Service\">\n"      \
 
 #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_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" \
         "  <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_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_exec_main_status_properties, &s->main_exec_status },
-                { "org.freedesktop.systemd1.Service", bus_unit_cgroup_properties,      u },
                 { NULL, }
         };
 
                 { NULL, }
         };
 
index 8a318faa554a1038faf2856882b6306bbe98e874..8243305848b1f3051840637cdb3af70b2646cceb 100644 (file)
 #include <errno.h>
 
 #include "dbus-unit.h"
 #include <errno.h>
 
 #include "dbus-unit.h"
-#include "dbus-slice.h"
 #include "dbus-common.h"
 #include "dbus-common.h"
+#include "dbus-cgroup.h"
 #include "selinux-access.h"
 #include "selinux-access.h"
+#include "dbus-slice.h"
 
 #define BUS_SLICE_INTERFACE                                             \
         " <interface name=\"org.freedesktop.systemd1.Slice\">\n"        \
 
 #define BUS_SLICE_INTERFACE                                             \
         " <interface name=\"org.freedesktop.systemd1.Slice\">\n"        \
-        BUS_UNIT_CGROUP_INTERFACE                                       \
         " </interface>\n"
 
 #define INTROSPECTION                                                   \
         " </interface>\n"
 
 #define INTROSPECTION                                                   \
 const char bus_slice_interface[] _introspect_("Slice") = BUS_SLICE_INTERFACE;
 
 DBusHandlerResult bus_slice_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
 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[] = {
         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, }
         };
 
                 { NULL, }
         };
 
index 973f905149c134279651008ef785f85b51c6f00e..7ec4f3392443b9e6840a802ab453625d6133f081 100644 (file)
 #include <errno.h>
 
 #include "dbus-unit.h"
 #include <errno.h>
 
 #include "dbus-unit.h"
-#include "dbus-socket.h"
 #include "dbus-execute.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-common.h"
 #include "selinux-access.h"
+#include "dbus-socket.h"
 
 #define BUS_SOCKET_INTERFACE                                            \
         " <interface name=\"org.freedesktop.systemd1.Socket\">\n"       \
 
 #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_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" \
         "  <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[] = {
 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, }
         };
 
                 { NULL, }
         };
 
index 2e99fba7dbc31176a86c8528c9feaa4847185f70..4ae1cd08e00c3415df2ea59f7984f4d387398d79 100644 (file)
 #include <errno.h>
 
 #include "dbus-unit.h"
 #include <errno.h>
 
 #include "dbus-unit.h"
-#include "dbus-swap.h"
 #include "dbus-execute.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-common.h"
 #include "selinux-access.h"
+#include "dbus-swap.h"
 
 #define BUS_SWAP_INTERFACE                                              \
         " <interface name=\"org.freedesktop.systemd1.Swap\">\n"         \
 
 #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_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"
         "  <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[] = {
 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, }
         };
 
                 { NULL, }
         };
 
index 8a7ab349d13c5445e5e0a75a410682e946d351db..cbd41342f42f54e2778fcd4ce52983b4bc94eea5 100644 (file)
@@ -295,90 +295,6 @@ static int bus_unit_append_job(DBusMessageIter *i, const char *property, void *d
         return 0;
 }
 
         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;
 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;
 
                 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
         } 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;
 }
 
         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 },
 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 },
         { "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, }
 };
         { NULL, }
 };
index 83932c5a6c14b0c3a0e2d31371dfa0869ed35ce8..1e226ef451dd5ccc5b312a672d7e44903f27d4e3 100644 (file)
         "  <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=\"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"
 
         " </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[];
 #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);
 
 void bus_unit_send_change_signal(Unit *u);
 void bus_unit_send_removed_signal(Unit *u);
index 1272c938cf55fffbdf0c4bcccfb2a379bc79d44a..c2097a4dbffb629c1274d1ed1915623b11d05141 100644 (file)
@@ -28,7 +28,6 @@
 #include "dbus.h"
 #include "log.h"
 #include "strv.h"
 #include "dbus.h"
 #include "log.h"
 #include "strv.h"
-#include "cgroup.h"
 #include "mkdir.h"
 #include "missing.h"
 #include "dbus-unit.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
                                            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);
         }
 
         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
                                            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 */
 
                 /* Forward the message to the system bus, so that user
                  * instances are notified as well */
index 9148d06df4697ea0fba78cc608d7d4e8dc8ba304..5e342f8d47af71fdf1afb3faeb7a38eb9c5d69b5 100644 (file)
@@ -55,7 +55,6 @@
 #include "sd-messages.h"
 #include "ioprio.h"
 #include "securebits.h"
 #include "sd-messages.h"
 #include "ioprio.h"
 #include "securebits.h"
-#include "cgroup.h"
 #include "namespace.h"
 #include "tcpwrap.h"
 #include "exit-status.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 "syscall-list.h"
 #include "env-util.h"
 #include "fileio.h"
+#include "unit.h"
 
 #define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
 
 
 #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,
                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) {
 
                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;
         pid_t pid;
         int r;
-        char *line;
-        int socket_fd;
-        _cleanup_strv_free_ char **files_env = NULL;
 
         assert(command);
         assert(context);
 
         assert(command);
         assert(context);
@@ -1042,17 +1041,6 @@ int exec_spawn(ExecCommand *command,
                         NULL);
         free(line);
 
                         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)
         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;
                 _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 */
 
 
                 /* child */
 
@@ -1185,8 +1172,8 @@ int exec_spawn(ExecCommand *command,
                         goto fail_child;
                 }
 
                         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;
                         if (err < 0) {
                                 r = EXIT_CGROUP;
                                 goto fail_child;
@@ -1269,36 +1256,6 @@ int exec_spawn(ExecCommand *command,
                                         goto fail_child;
                                 }
                         }
                                         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) {
                 }
 
                 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). */
          * 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);
 
 
         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->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;
 }
         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);
 
         assert(c);
         assert(f);
 
-        if (!prefix)
-                prefix = "";
+        prefix = strempty(prefix);
 
         fprintf(f,
                 "%sUMask: %04o\n"
 
         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"
                 "%sRootDirectory: %s\n"
                 "%sNonBlocking: %s\n"
                 "%sPrivateTmp: %s\n"
-                "%sControlGroupModify: %s\n"
-                "%sControlGroupPersistent: %s\n"
                 "%sPrivateNetwork: %s\n"
                 "%sIgnoreSIGPIPE: %s\n",
                 prefix, c->umask,
                 "%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, 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));
 
                 prefix, yes_no(c->private_network),
                 prefix, yes_no(c->ignore_sigpipe));
 
index 15574dc97e1766ac6c270c87f4fd51978c60ba95..c1e9717dc8007ea360fe0994cc800012e19a3c57 100644 (file)
@@ -33,14 +33,11 @@ typedef struct ExecContext ExecContext;
 #include <stdio.h>
 #include <sched.h>
 
 #include <stdio.h>
 #include <sched.h>
 
-struct CGroupBonding;
-struct CGroupAttribute;
-
-typedef struct Unit Unit;
-
 #include "list.h"
 #include "util.h"
 
 #include "list.h"
 #include "util.h"
 
+typedef struct Unit Unit;
+
 typedef enum ExecInput {
         EXEC_INPUT_NULL,
         EXEC_INPUT_TTY,
 typedef enum ExecInput {
         EXEC_INPUT_NULL,
         EXEC_INPUT_TTY,
@@ -148,9 +145,6 @@ struct ExecContext {
 
         bool no_new_privileges;
 
 
         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
         /* 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;
 };
 
         bool cpu_sched_set:1;
 };
 
+#include "cgroup.h"
+
 int exec_spawn(ExecCommand *command,
                char **argv,
                ExecContext *context,
 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,
                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);
                const char *unit_id,
                int pipe_fd[2],
                pid_t *ret);
index 9e5a408a3099e0a1f23f4a19c1843dcf66ac3602..aa07de0517ada702850c3809dd21146fb7d32fce 100644 (file)
@@ -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.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)
 )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.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)
 )m4_dnl
 Unit.Description,                config_parse_unit_string_printf,    0,                             offsetof(Unit, description)
 Unit.Documentation,              config_parse_documentation,         0,                             offsetof(Unit, documentation)
index 15fabe860e7e47b903f0a0fad3e4f4e9902237df..57c8156fdd4e6905fe6d60bf2583631112ed732c 100644 (file)
@@ -51,6 +51,7 @@
 #include "path-util.h"
 #include "syscall-list.h"
 #include "env-util.h"
 #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,
 
 #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;
 }
 
         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,
 #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");
 
 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,
 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;
 }
 
         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) {
 #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_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" },
                 { config_parse_unit_deps,             "UNIT [...]" },
                 { config_parse_exec,                  "PATH [ARGUMENT [...]]" },
                 { config_parse_service_type,          "SERVICETYPE" },
index f9677baa0fd44077f86fe94d1cc8095ded734c85..5e36f3538aa78634d069c02bb1aef12b33939567 100644 (file)
@@ -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_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);
 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_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_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);
 
 /* gperf prototypes */
 const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);
index c123de91cef2b52d3f95e3a4886d9753e10dc332..3c6fccf527d4adf7f0875b1a75cebce61182efac 100644 (file)
@@ -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 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;
 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", "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 },
                 { "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);
 
 
         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);
 
         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);
                 free(arg_default_rlimit[j]);
 
         free(arg_default_unit);
-        strv_free(arg_default_controllers);
         free_join_controllers();
 
         dbus_shutdown();
         free_join_controllers();
 
         dbus_shutdown();
index 2416dd0f1e2121788b0506db29077603e792a8e0..6ba51a41162c64f42dd1d1471c054c4c45134f77 100644 (file)
@@ -55,7 +55,6 @@
 #include "util.h"
 #include "mkdir.h"
 #include "ratelimit.h"
 #include "util.h"
 #include "mkdir.h"
 #include "ratelimit.h"
-#include "cgroup.h"
 #include "mount-setup.h"
 #include "unit-name.h"
 #include "dbus-unit.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);
 
 
         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;
 
         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->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)))
                 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);
 
         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);
         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 = 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;
                         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)
                 /* 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) {
 
                 /* 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_gc_queue(m) > 0)
                         continue;
 
+                if (manager_dispatch_cgroup_queue(m) > 0)
+                        continue;
+
                 if (manager_dispatch_dbus_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;
 }
 
         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;
 
 int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) {
         int i;
 
index f0bb2eb035645893a133ecc0bf6afccb9fd666d4..68cb2e4a3db224fd25591b6ae00d93ed36891b64 100644 (file)
@@ -27,6 +27,7 @@
 #include <dbus/dbus.h>
 
 #include "fdset.h"
 #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 */
 
 /* 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 "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
 
 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 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;
         Hashmap *watch_pids;  /* pid => Unit object n:1 */
 
         char *notify_socket;
@@ -139,7 +144,6 @@ struct Manager {
         Set *unit_path_cache;
 
         char **environment;
         Set *unit_path_cache;
 
         char **environment;
-        char **default_controllers;
 
         usec_t runtime_watchdog;
         usec_t shutdown_watchdog;
 
         usec_t runtime_watchdog;
         usec_t shutdown_watchdog;
@@ -198,7 +202,8 @@ struct Manager {
         int dev_autofs_fd;
 
         /* Data specific to the cgroup subsystem */
         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;
         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);
 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);
 int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit);
 
 int manager_loop(Manager *m);
index e21e774d4dc5d37defa4507cc2a20ea1ab0125db..c71d51bfa409ba678304c94c2c7adf73d19c47be 100644 (file)
@@ -82,6 +82,7 @@ static void mount_init(Unit *u) {
         }
 
         kill_context_init(&m->kill_context);
         }
 
         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
 
         /* 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);
 
         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;
         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;
 
         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;
         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);
 
         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;
 
         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;
 
                 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;
 
                 /* FIXME: we need to do something here */
                 goto fail;
 
@@ -1878,8 +1879,9 @@ const UnitVTable mount_vtable = {
                 "Mount\0"
                 "Install\0",
 
                 "Mount\0"
                 "Install\0",
 
+        .private_section = "Mount",
         .exec_context_offset = offsetof(Mount, exec_context),
         .exec_context_offset = offsetof(Mount, exec_context),
-        .exec_section = "Mount",
+        .cgroup_context_offset = offsetof(Mount, cgroup_context),
 
         .no_alias = true,
         .no_instances = true,
 
         .no_alias = true,
         .no_instances = true,
index bcc10ee0d4613c73b2123a5af40169f418ddc2d2..7cd4320d94e5ed7551211a5115ffdc2f00862a37 100644 (file)
@@ -25,6 +25,8 @@ typedef struct Mount Mount;
 
 #include "unit.h"
 #include "kill.h"
 
 #include "unit.h"
 #include "kill.h"
+#include "execute.h"
+#include "cgroup.h"
 
 typedef enum MountState {
         MOUNT_DEAD,
 
 typedef enum MountState {
         MOUNT_DEAD,
@@ -95,8 +97,10 @@ struct Mount {
         usec_t timeout_usec;
 
         ExecCommand exec_command[_MOUNT_EXEC_COMMAND_MAX];
         usec_t timeout_usec;
 
         ExecCommand exec_command[_MOUNT_EXEC_COMMAND_MAX];
+
         ExecContext exec_context;
         KillContext kill_context;
         ExecContext exec_context;
         KillContext kill_context;
+        CGroupContext cgroup_context;
 
         MountState state, deserialized_state;
 
 
         MountState state, deserialized_state;
 
index a0c648a85b6b257e7339d823f0dd3d0ac9a80866..5fdbdb13a343f42d180d9f9c093b2265f9b76eaa 100644 (file)
@@ -141,6 +141,7 @@ static void service_init(Unit *u) {
 
         exec_context_init(&s->exec_context);
         kill_context_init(&s->kill_context);
 
         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);
 
 
         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;
 
         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;
         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;
 
                 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)
 #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);
 
 
         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;
 
         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)
         /* 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,
 
         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;
         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);
 
 
         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 ||
         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;
                 }
 
                         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;
                 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;
         }
 
                 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,
         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,
                        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);
                        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);
 
 
         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;
 
         if (r < 0)
                 return r;
 
@@ -2123,10 +2132,21 @@ fail:
         service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
 }
 
         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) {
 static void service_enter_start(Service *s) {
+        ExecCommand *c;
         pid_t pid;
         int r;
         pid_t pid;
         int r;
-        ExecCommand *c;
 
         assert(s);
 
 
         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. */
         /* 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;
 
         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) {
 
         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. */
                 /* 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;
 
 
                 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) {
                 }
 
         } else if (s->control_pid == pid) {
-
                 s->control_pid = 0;
 
                 if (s->control_command) {
                 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 */
                 /* 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 &&
 
                 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);
         Service *s = SERVICE(u);
 
         assert(u);
@@ -3823,8 +3839,9 @@ const UnitVTable service_vtable = {
                 "Service\0"
                 "Install\0",
 
                 "Service\0"
                 "Install\0",
 
+        .private_section = "Service",
         .exec_context_offset = offsetof(Service, exec_context),
         .exec_context_offset = offsetof(Service, exec_context),
-        .exec_section = "Service",
+        .cgroup_context_offset = offsetof(Service, cgroup_context),
 
         .init = service_init,
         .done = service_done,
 
         .init = service_init,
         .done = service_done,
@@ -3857,7 +3874,7 @@ const UnitVTable service_vtable = {
 
         .reset_failed = service_reset_failed,
 
 
         .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,
         .notify_message = service_notify_message,
 
         .bus_name_owner_change = service_bus_name_owner_change,
index 703d3faa4519d70ec0acbe1c03aefaecb705792c..182cba1333673fd0edba91a286dda23949377e46 100644 (file)
@@ -135,6 +135,7 @@ struct Service {
 
         ExecContext exec_context;
         KillContext kill_context;
 
         ExecContext exec_context;
         KillContext kill_context;
+        CGroupContext cgroup_context;
 
         ServiceState state, deserialized_state;
 
 
         ServiceState state, deserialized_state;
 
index c1c33fe5c60b256c4e38d2f04b744a49b316d59d..df2d91e47308805049c2a9ade7dec7388e669374 100644 (file)
@@ -36,6 +36,23 @@ static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = {
         [SLICE_ACTIVE] = UNIT_ACTIVE
 };
 
         [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);
 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);
 }
 
         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;
         char *a, *dash;
-        int r;
         Unit *parent;
         Unit *parent;
+        int r;
 
         assert(s);
 
 
         assert(s);
 
-        if (UNIT_DEREF(UNIT(s)->slice))
+        if (UNIT_ISSET(UNIT(s)->slice))
                 return 0;
 
                 return 0;
 
-        a = strdupa(UNIT(s)->id);
-
-        dash = strrchr(a, '-');
-        if (!dash)
+        if (unit_has_name(UNIT(s), SPECIAL_ROOT_SLICE))
                 return 0;
 
                 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)
 
         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, '-');
 
                 a = strdupa(UNIT(s)->id);
                 dash = strrchr(a, '-');
-                if (dash) {
+                if (dash)
                         strcpy(dash, ".slice");
                         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);
 
 
         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) {
 
         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;
 
                 if (r < 0)
                         return r;
 
@@ -138,10 +158,6 @@ static int slice_load(Unit *u) {
                         if (r < 0)
                                 return r;
                 }
                         if (r < 0)
                                 return r;
                 }
-
-                r = unit_add_default_cgroups(UNIT(s));
-                if (r < 0)
-                        return r;
         }
 
         return slice_verify(s);
         }
 
         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));
         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);
 }
 
 static int slice_start(Unit *u) {
         Slice *t = SLICE(u);
-        int r;
 
         assert(t);
         assert(t->state == SLICE_DEAD);
 
 
         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;
 
         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);
 
         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;
 
         slice_set_state(t, SLICE_DEAD);
         return 0;
@@ -264,10 +277,16 @@ const UnitVTable slice_vtable = {
                 "Slice\0"
                 "Install\0",
 
                 "Slice\0"
                 "Install\0",
 
+        .private_section = "Slice",
+        .cgroup_context_offset = offsetof(Slice, cgroup_context),
+
         .no_alias = true,
         .no_instances = true,
 
         .no_alias = true,
         .no_instances = true,
 
+        .init = slice_init,
         .load = slice_load,
         .load = slice_load,
+        .done = slice_done,
+
         .coldplug = slice_coldplug,
 
         .dump = slice_dump,
         .coldplug = slice_coldplug,
 
         .dump = slice_dump,
@@ -288,11 +307,11 @@ const UnitVTable slice_vtable = {
 
         .status_message_formats = {
                 .finished_start_job = {
 
         .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_DEPENDENCY] = "Dependency failed for %s.",
                 },
                 .finished_stop_job = {
-                        [JOB_DONE]       = "Deinstalled slice %s.",
+                        [JOB_DONE]       = "Removed slice %s.",
                 },
         },
 };
                 },
         },
 };
index 4320a6354b27dd75e037cb7192388f3d8773bf11..ad0c63902b0ffd835420c6d15bc124015d0f8e09 100644 (file)
@@ -36,6 +36,8 @@ struct Slice {
         Unit meta;
 
         SliceState state, deserialized_state;
         Unit meta;
 
         SliceState state, deserialized_state;
+
+        CGroupContext cgroup_context;
 };
 
 extern const UnitVTable slice_vtable;
 };
 
 extern const UnitVTable slice_vtable;
index 2f25e25aa6e313f6f7aa8981e9b784781ddf4930..c1bbaec4477402f9eae3a5d29571dd40387155f1 100644 (file)
@@ -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);
         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;
 }
 
         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));
         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;
 
         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;
 
                 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;
                 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);
 
         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;
         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,
                        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);
                        UNIT(s)->id,
                        NULL,
                        &pid);
@@ -2361,8 +2361,9 @@ const UnitVTable socket_vtable = {
                 "Socket\0"
                 "Install\0",
 
                 "Socket\0"
                 "Install\0",
 
+        .private_section = "Socket",
         .exec_context_offset = offsetof(Socket, exec_context),
         .exec_context_offset = offsetof(Socket, exec_context),
-        .exec_section = "Socket",
+        .cgroup_context_offset = offsetof(Socket, cgroup_context),
 
         .init = socket_init,
         .done = socket_done,
 
         .init = socket_init,
         .done = socket_done,
index 9d48cde0a671e83778caed969ceb5f68379eff4c..15942c1c90f1897385a7e226b70f40330c706da6 100644 (file)
@@ -102,6 +102,7 @@ struct Socket {
         ExecCommand* exec_command[_SOCKET_EXEC_COMMAND_MAX];
         ExecContext exec_context;
         KillContext kill_context;
         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
 
         /* For Accept=no sockets refers to the one service we'll
         activate. For Accept=yes sockets is either NULL, or filled
index 337a0a43e98e610b79bb800726cd61fb3bb52362..6d252e7baac7b1653e24dbbae255e90edf153564 100644 (file)
 #define SPECIAL_SYSTEM_SLICE "system.slice"
 #define SPECIAL_USER_SLICE "user.slice"
 #define SPECIAL_MACHINE_SLICE "machine.slice"
 #define SPECIAL_SYSTEM_SLICE "system.slice"
 #define SPECIAL_USER_SLICE "user.slice"
 #define SPECIAL_MACHINE_SLICE "machine.slice"
+#define SPECIAL_ROOT_SLICE "-.slice"
index d6721a6b31002524da35ae40963a824477e874ef..0d4b4fa4f90dae63f7d3541dbc2a64ecb4bd20df 100644 (file)
@@ -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);
         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;
 
 
         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;
 
         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);
         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;
 
                 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)
                 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);
 
         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;
         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,
                        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);
                        UNIT(s)->id,
                        NULL,
                        &pid);
@@ -1327,8 +1327,9 @@ const UnitVTable swap_vtable = {
                 "Swap\0"
                 "Install\0",
 
                 "Swap\0"
                 "Install\0",
 
+        .private_section = "Swap",
         .exec_context_offset = offsetof(Swap, exec_context),
         .exec_context_offset = offsetof(Swap, exec_context),
-        .exec_section = "Swap",
+        .cgroup_context_offset = offsetof(Swap, cgroup_context),
 
         .no_alias = true,
         .no_instances = true,
 
         .no_alias = true,
         .no_instances = true,
index 121889d1d5e1b1c0760cd3862419898aeee7eb86..7e48c0ea3bb2827757d778d170a5d88cbf25a63c 100644 (file)
@@ -88,6 +88,7 @@ struct Swap {
         ExecCommand exec_command[_SWAP_EXEC_COMMAND_MAX];
         ExecContext exec_context;
         KillContext kill_context;
         ExecCommand exec_command[_SWAP_EXEC_COMMAND_MAX];
         ExecContext exec_context;
         KillContext kill_context;
+        CGroupContext cgroup_context;
 
         SwapState state, deserialized_state;
 
 
         SwapState state, deserialized_state;
 
index f75045dc488faf29c0a1ab9f2ccad2ec91572c6c..0dcf85b5e0d3f242b633195348fc1a9a2c4b77aa 100644 (file)
@@ -44,7 +44,6 @@
 #include "special.h"
 #include "cgroup-util.h"
 #include "missing.h"
 #include "special.h"
 #include "cgroup-util.h"
 #include "missing.h"
-#include "cgroup-attr.h"
 #include "mkdir.h"
 #include "label.h"
 #include "fileio-label.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--;
         }
 
                 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);
         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\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),
                 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(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);
 
         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) {
         }
 
         if (u->load_state == UNIT_LOADED) {
-                CGroupBonding *b;
-                CGroupAttribute *a;
 
                 fprintf(f,
                         "%s\tStopWhenUnneeded: %s\n"
 
                 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));
 
                         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);
 
                 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 */
         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 */
                 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;
                 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 */
          * 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 */
                 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;
                 return r;
 
         return 0;
@@ -880,8 +874,12 @@ static int unit_add_default_dependencies(Unit *u) {
                                 return r;
                 }
 
                                 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;
         }
                 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))
         }
 
         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);
 
         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);
 }
 
         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);
 
 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;
                 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);
 }
 
                                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;
 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 (UNIT_ISSET(u->slice))
                 return 0;
 
-        if (u->manager->running_as != SYSTEMD_SYSTEM)
+        if (!unit_get_cgroup_context(u))
                 return 0;
 
                 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;
 
         if (r < 0)
                 return r;
 
@@ -2197,148 +2018,6 @@ const char *unit_slice_name(Unit *u) {
         return UNIT_DEREF(u->slice)->id;
 }
 
         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;
 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 (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;
 
                 _cleanup_set_free_ Set *pid_set = NULL;
                 int q;
 
@@ -2825,7 +2504,7 @@ int unit_kill_common(
                                 return q;
                 }
 
                                 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;
         }
                 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 */
         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);
         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);
 }
 
         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;
 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;
         }
 
                         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);
                 _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;
                 }
 
                                 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));
                 if (r < 0) {
                         if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
                                 log_warning_unit(u->id, "Failed to kill control group: %s", strerror(-r));
index da52101bd2f6220977fafe7ea7ebad0711f8d917..fbcaabe167ed346276c7523e311d59b6bec05952 100644 (file)
@@ -37,10 +37,10 @@ typedef struct UnitStatusMessageFormats UnitStatusMessageFormats;
 #include "list.h"
 #include "socket-util.h"
 #include "execute.h"
 #include "list.h"
 #include "socket-util.h"
 #include "execute.h"
+#include "cgroup.h"
 #include "condition.h"
 #include "install.h"
 #include "unit-name.h"
 #include "condition.h"
 #include "install.h"
 #include "unit-name.h"
-#include "cgroup-semantics.h"
 
 enum UnitActiveState {
         UNIT_ACTIVE,
 
 enum UnitActiveState {
         UNIT_ACTIVE,
@@ -115,8 +115,6 @@ enum UnitDependency {
 
 #include "manager.h"
 #include "job.h"
 
 #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
 
 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 */
         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;
 
 
         UnitRef slice;
 
@@ -197,6 +196,9 @@ struct Unit {
         /* GC queue */
         LIST_FIELDS(Unit, gc_queue);
 
         /* GC queue */
         LIST_FIELDS(Unit, gc_queue);
 
+        /* CGroup realize members queue */
+        LIST_FIELDS(Unit, cgroup_queue);
+
         /* Used during GC sweeps */
         unsigned gc_marker;
 
         /* 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_dbus_queue:1;
         bool in_cleanup_queue:1;
         bool in_gc_queue:1;
+        bool in_cgroup_queue:1;
 
         bool sent_dbus_new_signal: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;
 
          * 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 */
 
         /* 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 */
 
         /* 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);
 
         /* 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_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);
 
 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_;
 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);
 
 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);
index 347e5aa022615d42203cd15d9d40adafcbee282e..0b35a9e2d07ef3a737117b28e4638e8628fff4e4 100644 (file)
@@ -223,7 +223,7 @@ static int machine_create_one_group(Machine *m, const char *controller, const ch
                 r = -EINVAL;
 
         if (r < 0) {
                 r = -EINVAL;
 
         if (r < 0) {
-                r = cg_create(controller, path, NULL);
+                r = cg_create(controller, path);
                 if (r < 0)
                         return r;
         }
                 if (r < 0)
                         return r;
         }
index aba517d1f7b5589be33df974f3a995c41bd2422a..760425329b70253eb2d8bf1523211cc2143cc471 100644 (file)
@@ -472,12 +472,12 @@ static int session_create_one_group(Session *s, const char *controller, const ch
                 r = -EINVAL;
 
         if (r < 0) {
                 r = -EINVAL;
 
         if (r < 0) {
-                r = cg_create(controller, path, NULL);
+                r = cg_create(controller, path);
                 if (r < 0)
                         return r;
         }
 
                 if (r < 0)
                         return r;
         }
 
-        r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid, -1);
+        r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid);
         if (r >= 0)
                 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
 
         if (r >= 0)
                 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
 
index fb0c9b75d759e60d4e803e64ecd8668b06aa1cce..9f7b924a243a9720f1d605af4c7d0d46487a445c 100644 (file)
@@ -349,7 +349,7 @@ static int user_create_cgroup(User *u) {
                         return log_oom();
         }
 
                         return log_oom();
         }
 
-        r = cg_create(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL);
+        r = cg_create(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
         if (r < 0) {
                 log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", u->cgroup_path, strerror(-r));
                 return r;
         if (r < 0) {
                 log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", u->cgroup_path, strerror(-r));
                 return r;
@@ -360,7 +360,7 @@ static int user_create_cgroup(User *u) {
                 if (strv_contains(u->manager->reset_controllers, *k))
                         continue;
 
                 if (strv_contains(u->manager->reset_controllers, *k))
                         continue;
 
-                r = cg_create(*k, u->cgroup_path, NULL);
+                r = cg_create(*k, u->cgroup_path);
                 if (r < 0)
                         log_warning("Failed to create cgroup %s:%s: %s", *k, u->cgroup_path, strerror(-r));
         }
                 if (r < 0)
                         log_warning("Failed to create cgroup %s:%s: %s", *k, u->cgroup_path, strerror(-r));
         }
index 5b5163c250e1b8e60fbba2e9c55715633577a2c7..574a7be3ee127f1ff3d265aa01cda43762373e81 100644 (file)
 #include "util.h"
 #include "mkdir.h"
 
 #include "util.h"
 #include "mkdir.h"
 
-int cg_create(const char *controller, const char *path, const char *suffix) {
+/* This is split out since it needs label calls, either directly or
+ * indirectly. */
+
+int cg_create(const char *controller, const char *path) {
         _cleanup_free_ char *fs = NULL;
         int r;
 
         _cleanup_free_ char *fs = NULL;
         int r;
 
-        r = cg_get_path_and_check(controller, path, suffix, &fs);
+        r = cg_get_path_and_check(controller, path, NULL, &fs);
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
-        r = mkdir_parents_label(fs, 0755);
+        r = mkdir_parents_prefix("/sys/fs/cgroup", fs, 0755);
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
@@ -64,7 +67,7 @@ int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
 
         assert(pid >= 0);
 
 
         assert(pid >= 0);
 
-        r = cg_create(controller, path, NULL);
+        r = cg_create(controller, path);
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
index 83cc0731b852d2357b6215da6ad8252bf9a5db3a..e971f36190e216300e9641dec89bc95744265473 100644 (file)
@@ -241,7 +241,6 @@ static int show_extra_pids(const char *controller, const char *path, const char
         unsigned i, j;
         int r;
 
         unsigned i, j;
         int r;
 
-        assert(controller);
         assert(path);
 
         if (n_pids <= 0)
         assert(path);
 
         if (n_pids <= 0)
index 9cbc64a5412fea7e78a72f0e33d77f9f7a7c5716..5816b7d4d6fd991a3c4d9cb8ce17ba978a8ab502 100644 (file)
@@ -132,7 +132,7 @@ int cg_read_subgroup(DIR *d, char **fn) {
         return 0;
 }
 
         return 0;
 }
 
-int cg_rmdir(const char *controller, const char *path, bool honour_sticky) {
+int cg_rmdir(const char *controller, const char *path) {
         _cleanup_free_ char *p = NULL;
         int r;
 
         _cleanup_free_ char *p = NULL;
         int r;
 
@@ -140,34 +140,6 @@ int cg_rmdir(const char *controller, const char *path, bool honour_sticky) {
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
-        if (honour_sticky) {
-                char *fn;
-
-                /* If the sticky bit is set on cgroup.procs, don't
-                 * remove the directory */
-
-                fn = strappend(p, "/cgroup.procs");
-                if (!fn)
-                        return -ENOMEM;
-
-                r = file_is_priv_sticky(fn);
-                free(fn);
-
-                if (r > 0)
-                        return 0;
-
-                /* Compatibility ... */
-                fn = strappend(p, "/tasks");
-                if (!fn)
-                        return -ENOMEM;
-
-                r = file_is_priv_sticky(fn);
-                free(fn);
-
-                if (r > 0)
-                        return 0;
-        }
-
         r = rmdir(p);
         if (r < 0 && errno != ENOENT)
                 return -errno;
         r = rmdir(p);
         if (r < 0 && errno != ENOENT)
                 return -errno;
@@ -298,7 +270,7 @@ int cg_kill_recursive(const char *controller, const char *path, int sig, bool si
                 ret = r;
 
         if (rem) {
                 ret = r;
 
         if (rem) {
-                r = cg_rmdir(controller, path, true);
+                r = cg_rmdir(controller, path);
                 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
                         return r;
         }
                 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
                         return r;
         }
@@ -407,7 +379,14 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char
         return ret;
 }
 
         return ret;
 }
 
-int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self, bool rem) {
+int cg_migrate_recursive(
+                const char *cfrom,
+                const char *pfrom,
+                const char *cto,
+                const char *pto,
+                bool ignore_self,
+                bool rem) {
+
         _cleanup_closedir_ DIR *d = NULL;
         int r, ret = 0;
         char *fn;
         _cleanup_closedir_ DIR *d = NULL;
         int r, ret = 0;
         char *fn;
@@ -448,7 +427,7 @@ int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto,
                 ret = r;
 
         if (rem) {
                 ret = r;
 
         if (rem) {
-                r = cg_rmdir(cfrom, pfrom, true);
+                r = cg_rmdir(cfrom, pfrom);
                 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
                         return r;
         }
                 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
                         return r;
         }
@@ -558,8 +537,9 @@ int cg_get_path_and_check(const char *controller, const char *path, const char *
 }
 
 static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
 }
 
 static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
-        char *p;
-        bool is_sticky;
+        assert(path);
+        assert(sb);
+        assert(ftwbuf);
 
         if (typeflag != FTW_DP)
                 return 0;
 
         if (typeflag != FTW_DP)
                 return 0;
@@ -567,31 +547,6 @@ static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct
         if (ftwbuf->level < 1)
                 return 0;
 
         if (ftwbuf->level < 1)
                 return 0;
 
-        p = strappend(path, "/cgroup.procs");
-        if (!p) {
-                errno = ENOMEM;
-                return 1;
-        }
-
-        is_sticky = file_is_priv_sticky(p) > 0;
-        free(p);
-
-        if (is_sticky)
-                return 0;
-
-        /* Compatibility */
-        p = strappend(path, "/tasks");
-        if (!p) {
-                errno = ENOMEM;
-                return 1;
-        }
-
-        is_sticky = file_is_priv_sticky(p) > 0;
-        free(p);
-
-        if (is_sticky)
-                return 0;
-
         rmdir(path);
         return 0;
 }
         rmdir(path);
         return 0;
 }
@@ -611,28 +566,8 @@ int cg_trim(const char *controller, const char *path, bool delete_root) {
                 r = errno ? -errno : -EIO;
 
         if (delete_root) {
                 r = errno ? -errno : -EIO;
 
         if (delete_root) {
-                bool is_sticky;
-                char *p;
-
-                p = strappend(fs, "/cgroup.procs");
-                if (!p)
-                        return -ENOMEM;
-
-                is_sticky = file_is_priv_sticky(p) > 0;
-                free(p);
-
-                if (!is_sticky) {
-                        p = strappend(fs, "/tasks");
-                        if (!p)
-                                return -ENOMEM;
-
-                        is_sticky = file_is_priv_sticky(p) > 0;
-                        free(p);
-                }
-
-                if (!is_sticky)
-                        if (rmdir(fs) < 0 && errno != ENOENT && r == 0)
-                                return -errno;
+                if (rmdir(fs) < 0 && errno != ENOENT)
+                        return -errno;
         }
 
         return r;
         }
 
         return r;
@@ -699,15 +634,14 @@ int cg_set_task_access(
                 const char *path,
                 mode_t mode,
                 uid_t uid,
                 const char *path,
                 mode_t mode,
                 uid_t uid,
-                gid_t gid,
-                int sticky) {
+                gid_t gid) {
 
         _cleanup_free_ char *fs = NULL, *procs = NULL;
         int r;
 
         assert(path);
 
 
         _cleanup_free_ char *fs = NULL, *procs = NULL;
         int r;
 
         assert(path);
 
-        if (mode == (mode_t) -1 && uid == (uid_t) -1 && gid == (gid_t) -1 && sticky < 0)
+        if (mode == (mode_t) -1 && uid == (uid_t) -1 && gid == (gid_t) -1)
                 return 0;
 
         if (mode != (mode_t) -1)
                 return 0;
 
         if (mode != (mode_t) -1)
@@ -717,28 +651,6 @@ int cg_set_task_access(
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
-        if (sticky >= 0 && mode != (mode_t) -1)
-                /* Both mode and sticky param are passed */
-                mode |= (sticky ? S_ISVTX : 0);
-        else if ((sticky >= 0 && mode == (mode_t) -1) ||
-                 (mode != (mode_t) -1 && sticky < 0)) {
-                struct stat st;
-
-                /* Only one param is passed, hence read the current
-                 * mode from the file itself */
-
-                r = lstat(fs, &st);
-                if (r < 0)
-                        return -errno;
-
-                if (mode == (mode_t) -1)
-                        /* No mode set, we just shall set the sticky bit */
-                        mode = (st.st_mode & ~S_ISVTX) | (sticky ? S_ISVTX : 0);
-                else
-                        /* Only mode set, leave sticky bit untouched */
-                        mode = (st.st_mode & ~0777) | mode;
-        }
-
         r = chmod_and_chown(fs, mode, uid, gid);
         if (r < 0)
                 return r;
         r = chmod_and_chown(fs, mode, uid, gid);
         if (r < 0)
                 return r;
@@ -1688,3 +1600,148 @@ int cg_slice_to_path(const char *unit, char **ret) {
 
         return 0;
 }
 
         return 0;
 }
+
+int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value) {
+        _cleanup_free_ char *p = NULL;
+        int r;
+
+        r = cg_get_path(controller, path, attribute, &p);
+        if (r < 0)
+                return r;
+
+        return write_string_file(p, value);
+}
+
+static const char mask_names[] =
+        "cpu\0"
+        "cpuacct\0"
+        "blkio\0"
+        "memory\0"
+        "devices\0";
+
+int cg_create_with_mask(CGroupControllerMask mask, const char *path) {
+        CGroupControllerMask bit = 1;
+        const char *n;
+        int r;
+
+        /* This one will create a cgroup in our private tree, but also
+         * duplicate it in the trees specified in mask, and remove it
+         * in all others */
+
+        /* First create the cgroup in our own hierarchy. */
+        r = cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
+        if (r < 0)
+                return r;
+
+        /* Then, do the same in the other hierarchies */
+        NULSTR_FOREACH(n, mask_names) {
+                if (bit & mask)
+                        cg_create(n, path);
+                else
+                        cg_trim(n, path, true);
+
+                bit <<= 1;
+        }
+
+        return r;
+}
+
+int cg_attach_with_mask(CGroupControllerMask mask, const char *path, pid_t pid) {
+        CGroupControllerMask bit = 1;
+        const char *n;
+        int r;
+
+        r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
+
+        NULSTR_FOREACH(n, mask_names) {
+                if (bit & mask)
+                        cg_attach(n, path, pid);
+                else {
+                        char prefix[strlen(path) + 1], *slash;
+
+                        /* OK, this one is a bit harder... Now we need
+                         * to add to the closest parent cgroup we
+                         * can find */
+                        strcpy(prefix, path);
+                        while ((slash = strrchr(prefix, '/'))) {
+                                int q;
+                                *slash = 0;
+
+                                q = cg_attach(n, prefix, pid);
+                                if (q >= 0)
+                                        break;
+                        }
+                }
+
+                bit <<= 1;
+        }
+
+        return r;
+}
+
+int cg_migrate_with_mask(CGroupControllerMask mask, const char *from, const char *to) {
+        CGroupControllerMask bit = 1;
+        const char *n;
+        int r;
+
+        if (path_equal(from, to))
+                return 0;
+
+        r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true);
+
+        NULSTR_FOREACH(n, mask_names) {
+                if (bit & mask)
+                        cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, to, n, to, false, false);
+                else {
+                        char prefix[strlen(to) + 1], *slash;
+
+                        strcpy(prefix, to);
+                        while ((slash = strrchr(prefix, '/'))) {
+                                int q;
+
+                                *slash = 0;
+
+                                q = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, to, n, prefix, false, false);
+                                if (q >= 0)
+                                        break;
+                        }
+                }
+
+                bit <<= 1;
+        }
+
+        return r;
+}
+
+int cg_trim_with_mask(CGroupControllerMask mask, const char *path, bool delete_root) {
+        CGroupControllerMask bit = 1;
+        const char *n;
+        int r;
+
+        r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
+        if (r < 0)
+                return r;
+
+        NULSTR_FOREACH(n, mask_names) {
+                if (bit & mask)
+                        cg_trim(n, path, delete_root);
+
+                bit <<= 1;
+        }
+
+        return r;
+}
+
+CGroupControllerMask cg_mask_supported(void) {
+        CGroupControllerMask bit = 1, mask = 0;
+        const char *n;
+
+        NULSTR_FOREACH(n, mask_names) {
+                if (check_hierarchy(n) >= 0)
+                        mask |= bit;
+
+                bit <<= 1;
+        }
+
+        return mask;
+}
index 2d00bb3fff11ab943f89fc4d9261e68bab04a9d5..9883d941c2425ce2b1faed9306f5c611adad05fe 100644 (file)
 #include "set.h"
 #include "def.h"
 
 #include "set.h"
 #include "def.h"
 
+/* A bit mask of well known cgroup controllers */
+typedef enum CGroupControllerMask {
+        CGROUP_CPU = 1,
+        CGROUP_CPUACCT = 2,
+        CGROUP_BLKIO = 4,
+        CGROUP_MEMORY = 8,
+        CGROUP_DEVICE = 16
+} CGroupControllerMask;
+
 /*
  * General rules:
  *
 /*
  * General rules:
  *
@@ -67,15 +76,17 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path);
 
 int cg_trim(const char *controller, const char *path, bool delete_root);
 
 
 int cg_trim(const char *controller, const char *path, bool delete_root);
 
-int cg_rmdir(const char *controller, const char *path, bool honour_sticky);
+int cg_rmdir(const char *controller, const char *path);
 int cg_delete(const char *controller, const char *path);
 
 int cg_delete(const char *controller, const char *path);
 
-int cg_create(const char *controller, const char *path, const char *suffix);
+int cg_create(const char *controller, const char *path);
 int cg_attach(const char *controller, const char *path, pid_t pid);
 int cg_create_and_attach(const char *controller, const char *path, pid_t pid);
 
 int cg_attach(const char *controller, const char *path, pid_t pid);
 int cg_create_and_attach(const char *controller, const char *path, pid_t pid);
 
+int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value);
+
 int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid);
 int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid);
-int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid, int sticky);
+int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid);
 
 int cg_install_release_agent(const char *controller, const char *agent);
 
 
 int cg_install_release_agent(const char *controller, const char *agent);
 
@@ -113,3 +124,10 @@ char *cg_unescape(const char *p) _pure_;
 bool cg_controller_is_valid(const char *p, bool allow_named);
 
 int cg_slice_to_path(const char *unit, char **ret);
 bool cg_controller_is_valid(const char *p, bool allow_named);
 
 int cg_slice_to_path(const char *unit, char **ret);
+
+int cg_create_with_mask(CGroupControllerMask mask, const char *path);
+int cg_attach_with_mask(CGroupControllerMask mask, const char *path, pid_t pid);
+int cg_migrate_with_mask(CGroupControllerMask mask, const char *from, const char *to);
+int cg_trim_with_mask(CGroupControllerMask mask, const char *path, bool delete_root);
+
+CGroupControllerMask cg_mask_supported(void);
index ad068bf30da6c4687b80393a6c387ca388ee74ea..dc13c9ee636f0ce8312f40ae152a038131fa8c36 100644 (file)
@@ -24,7 +24,6 @@
 #include "util.h"
 #include "strv.h"
 
 #include "util.h"
 #include "strv.h"
 
-
 int write_string_to_file(FILE *f, const char *line) {
         errno = 0;
         fputs(line, f);
 int write_string_to_file(FILE *f, const char *line) {
         errno = 0;
         fputs(line, f);
index 0e51b64f69331d21228b2dcc1621fb29df18f274..e21a0f398949fd90d614c07a2f0e600a0ebb2cf3 100644 (file)
 #include <stdlib.h>
 #include <stdio.h>
 
 #include <stdlib.h>
 #include <stdio.h>
 
-#include "mkdir.h"
 #include "label.h"
 #include "util.h"
 #include "label.h"
 #include "util.h"
+#include "path-util.h"
+#include "mkdir.h"
 
 int mkdir_label(const char *path, mode_t mode) {
         return label_mkdir(path, mode, true);
 }
 
 
 int mkdir_label(const char *path, mode_t mode) {
         return label_mkdir(path, mode, true);
 }
 
-static int makedir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, bool apply) {
+static int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, bool apply) {
         struct stat st;
 
         if (label_mkdir(path, mode, apply) >= 0)
         struct stat st;
 
         if (label_mkdir(path, mode, apply) >= 0)
@@ -56,36 +57,50 @@ static int makedir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, boo
 }
 
 int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid) {
 }
 
 int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid) {
-        return makedir_safe(path, mode, uid, gid, false);
+        return mkdir_safe_internal(path, mode, uid, gid, false);
 }
 
 int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid) {
 }
 
 int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid) {
-        return makedir_safe(path, mode, uid, gid, true);
+        return mkdir_safe_internal(path, mode, uid, gid, true);
 }
 
 }
 
-static int makedir_parents(const char *path, mode_t mode, bool apply) {
+static int is_dir(const char* path) {
         struct stat st;
         struct stat st;
+
+        if (stat(path, &st) < 0)
+                return -errno;
+
+        return S_ISDIR(st.st_mode);
+}
+
+static int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, bool apply) {
         const char *p, *e;
         const char *p, *e;
+        int r;
 
         assert(path);
 
 
         assert(path);
 
+        if (prefix && !path_startswith(path, prefix))
+                return -ENOTDIR;
+
         /* return immediately if directory exists */
         e = strrchr(path, '/');
         if (!e)
                 return -EINVAL;
         /* return immediately if directory exists */
         e = strrchr(path, '/');
         if (!e)
                 return -EINVAL;
+
+        if (e == path)
+                return 0;
+
         p = strndupa(path, e - path);
         p = strndupa(path, e - path);
-        if (stat(p, &st) >= 0) {
-                if ((st.st_mode & S_IFMT) == S_IFDIR)
-                        return 0;
-                else
-                        return -ENOTDIR;
-        }
+        r = is_dir(p);
+        if (r > 0)
+                return 0;
+        if (r == 0)
+                return -ENOTDIR;
 
         /* create every parent directory in the path, except the last component */
         p = path + strspn(path, "/");
         for (;;) {
 
         /* create every parent directory in the path, except the last component */
         p = path + strspn(path, "/");
         for (;;) {
-                int r;
-                char *t;
+                char t[strlen(path) + 1];
 
                 e = p + strcspn(p, "/");
                 p = e + strspn(e, "/");
 
                 e = p + strcspn(p, "/");
                 p = e + strspn(e, "/");
@@ -95,39 +110,36 @@ static int makedir_parents(const char *path, mode_t mode, bool apply) {
                 if (*p == 0)
                         return 0;
 
                 if (*p == 0)
                         return 0;
 
-                t = strndup(path, e - path);
-                if (!t)
-                        return -ENOMEM;
+                memcpy(t, path, e - path);
+                t[e-path] = 0;
 
 
-                r = label_mkdir(t, mode, apply);
-                free(t);
+                if (prefix && path_startswith(prefix, t))
+                        continue;
 
 
+                r = label_mkdir(t, mode, apply);
                 if (r < 0 && errno != EEXIST)
                         return -errno;
         }
 }
 
 int mkdir_parents(const char *path, mode_t mode) {
                 if (r < 0 && errno != EEXIST)
                         return -errno;
         }
 }
 
 int mkdir_parents(const char *path, mode_t mode) {
-        return makedir_parents(path, mode, false);
+        return mkdir_parents_internal(NULL, path, mode, false);
 }
 
 int mkdir_parents_label(const char *path, mode_t mode) {
 }
 
 int mkdir_parents_label(const char *path, mode_t mode) {
-        return makedir_parents(path, mode, true);
+        return mkdir_parents_internal(NULL, path, mode, true);
 }
 
 }
 
-static int is_dir(const char* path) {
-        struct stat st;
-        if (stat(path, &st) < 0)
-                return -errno;
-        return S_ISDIR(st.st_mode);
+int mkdir_parents_prefix(const char *prefix, const char *path, mode_t mode) {
+        return mkdir_parents_internal(prefix, path, mode, true);
 }
 
 }
 
-static int makedir_p(const char *path, mode_t mode, bool apply) {
+static int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, bool apply) {
         int r;
 
         /* Like mkdir -p */
 
         int r;
 
         /* Like mkdir -p */
 
-        r = makedir_parents(path, mode, apply);
+        r = mkdir_parents_internal(prefix, path, mode, apply);
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
@@ -139,9 +151,13 @@ static int makedir_p(const char *path, mode_t mode, bool apply) {
 }
 
 int mkdir_p(const char *path, mode_t mode) {
 }
 
 int mkdir_p(const char *path, mode_t mode) {
-        return makedir_p(path, mode, false);
+        return mkdir_p_internal(NULL, path, mode, false);
 }
 
 int mkdir_p_label(const char *path, mode_t mode) {
 }
 
 int mkdir_p_label(const char *path, mode_t mode) {
-        return makedir_p(path, mode, true);
+        return mkdir_p_internal(NULL, path, mode, true);
+}
+
+int mkdir_p_prefix(const char *prefix, const char *path, mode_t mode) {
+        return mkdir_p_internal(prefix, path, mode, false);
 }
 }
index ce1c35e9baab94dbce903ff3056d57d67da6a47f..3d39b2910f28e69ce00c45464c7773e239ec90e2 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <sys/types.h>
+
 int mkdir_label(const char *path, mode_t mode);
 int mkdir_label(const char *path, mode_t mode);
+
 int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid);
 int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid);
 int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid);
 int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid);
+
 int mkdir_parents(const char *path, mode_t mode);
 int mkdir_parents_label(const char *path, mode_t mode);
 int mkdir_parents(const char *path, mode_t mode);
 int mkdir_parents_label(const char *path, mode_t mode);
+int mkdir_parents_prefix(const char *prefix, const char *path, mode_t mode);
+
 int mkdir_p(const char *path, mode_t mode);
 int mkdir_p_label(const char *path, mode_t mode);
 int mkdir_p(const char *path, mode_t mode);
 int mkdir_p_label(const char *path, mode_t mode);
+int mkdir_p_prefix(const char *prefix, const char *path, mode_t mode);
+
 #endif
 #endif
index 24543ee06db3d6e0dcd1112d14a582e0a28b6917..a4f8f2326e99e6582284429a0b71f94773618c22 100644 (file)
@@ -2378,150 +2378,6 @@ static int kill_unit(DBusConnection *bus, char **args) {
         return 0;
 }
 
         return 0;
 }
 
-static int set_cgroup(DBusConnection *bus, char **args) {
-        _cleanup_free_ char *n = NULL;
-        const char *method, *runtime;
-        char **argument;
-        int r;
-
-        assert(bus);
-        assert(args);
-
-        method =
-                streq(args[0], "set-cgroup")   ? "SetUnitControlGroup" :
-                streq(args[0], "unset-cgroup") ? "UnsetUnitControlGroup"
-                                               : "UnsetUnitControlGroupAttribute";
-
-        runtime = arg_runtime ? "runtime" : "persistent";
-
-        n = unit_name_mangle(args[1]);
-        if (!n)
-                return log_oom();
-
-        STRV_FOREACH(argument, args + 2) {
-
-                r = bus_method_call_with_reply(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                method,
-                                NULL,
-                                NULL,
-                                DBUS_TYPE_STRING, &n,
-                                DBUS_TYPE_STRING, argument,
-                                DBUS_TYPE_STRING, &runtime,
-                                DBUS_TYPE_INVALID);
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static int set_cgroup_attr(DBusConnection *bus, char **args) {
-        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
-        DBusError error;
-        DBusMessageIter iter;
-        _cleanup_free_ char *n = NULL;
-        const char *runtime;
-        int r;
-
-        assert(bus);
-        assert(args);
-
-        dbus_error_init(&error);
-
-        runtime = arg_runtime ? "runtime" : "persistent";
-
-        n = unit_name_mangle(args[1]);
-        if (!n)
-                return log_oom();
-
-        m = dbus_message_new_method_call(
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "SetUnitControlGroupAttribute");
-        if (!m)
-                return log_oom();
-
-        dbus_message_iter_init_append(m, &iter);
-        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n) ||
-            !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args[2]))
-                return log_oom();
-
-        r = bus_append_strv_iter(&iter, args + 3);
-        if (r < 0)
-                return log_oom();
-
-        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
-                return log_oom();
-
-        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
-        if (!reply) {
-                log_error("Failed to issue method call: %s", bus_error_message(&error));
-                dbus_error_free(&error);
-                return -EIO;
-        }
-
-        return 0;
-}
-
-static int get_cgroup_attr(DBusConnection *bus, char **args) {
-        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
-        _cleanup_free_ char *n = NULL;
-        char **argument;
-        int r;
-
-        assert(bus);
-        assert(args);
-
-        n = unit_name_mangle(args[1]);
-        if (!n)
-                return log_oom();
-
-        STRV_FOREACH(argument, args + 2) {
-                _cleanup_strv_free_ char **list = NULL;
-                DBusMessageIter iter;
-                char **a;
-
-                r = bus_method_call_with_reply(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "GetUnitControlGroupAttribute",
-                                &reply,
-                                NULL,
-                                DBUS_TYPE_STRING, &n,
-                                DBUS_TYPE_STRING, argument,
-                                DBUS_TYPE_INVALID);
-                if (r < 0)
-                        return r;
-
-                if (!dbus_message_iter_init(reply, &iter)) {
-                        log_error("Failed to initialize iterator.");
-                        return -EIO;
-                }
-
-                r = bus_parse_strv_iter(&iter, &list);
-                if (r < 0) {
-                        log_error("Failed to parse value list.");
-                        return r;
-                }
-
-                STRV_FOREACH(a, list) {
-                        if (endswith(*a, "\n"))
-                                fputs(*a, stdout);
-                        else
-                                puts(*a);
-                }
-        }
-
-        return 0;
-}
-
 typedef struct ExecStatusInfo {
         char *name;
 
 typedef struct ExecStatusInfo {
         char *name;
 
@@ -2639,7 +2495,7 @@ typedef struct UnitStatusInfo {
 
         const char *fragment_path;
         const char *source_path;
 
         const char *fragment_path;
         const char *source_path;
-        const char *default_control_group;
+        const char *control_group;
 
         char **dropin_paths;
 
 
         char **dropin_paths;
 
@@ -2922,11 +2778,11 @@ static void print_status_info(UnitStatusInfo *i) {
         if (i->status_text)
                 printf("   Status: \"%s\"\n", i->status_text);
 
         if (i->status_text)
                 printf("   Status: \"%s\"\n", i->status_text);
 
-        if (i->default_control_group &&
-            (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) {
+        if (i->control_group &&
+            (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->control_group, false) == 0)) {
                 unsigned c;
 
                 unsigned c;
 
-                printf("   CGroup: %s\n", i->default_control_group);
+                printf("   CGroup: %s\n", i->control_group);
 
                 if (arg_transport != TRANSPORT_SSH) {
                         unsigned k = 0;
 
                 if (arg_transport != TRANSPORT_SSH) {
                         unsigned k = 0;
@@ -2945,7 +2801,7 @@ static void print_status_info(UnitStatusInfo *i) {
                         if (i->control_pid > 0)
                                 extra[k++] = i->control_pid;
 
                         if (i->control_pid > 0)
                                 extra[k++] = i->control_pid;
 
-                        show_cgroup_and_extra_by_spec(i->default_control_group, prefix,
+                        show_cgroup_and_extra_by_spec(i->control_group, prefix,
                                                       c, false, extra, k, flags);
                 }
         }
                                                       c, false, extra, k, flags);
                 }
         }
@@ -3054,8 +2910,12 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
                                 i->fragment_path = s;
                         else if (streq(name, "SourcePath"))
                                 i->source_path = s;
                                 i->fragment_path = s;
                         else if (streq(name, "SourcePath"))
                                 i->source_path = s;
+#ifndef LEGACY
                         else if (streq(name, "DefaultControlGroup"))
                         else if (streq(name, "DefaultControlGroup"))
-                                i->default_control_group = s;
+                                i->control_group = s;
+#endif
+                        else if (streq(name, "ControlGroup"))
+                                i->control_group = s;
                         else if (streq(name, "StatusText"))
                                 i->status_text = s;
                         else if (streq(name, "PIDFile"))
                         else if (streq(name, "StatusText"))
                                 i->status_text = s;
                         else if (streq(name, "PIDFile"))
@@ -3457,8 +3317,44 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                         }
 
                         return 0;
                         }
 
                         return 0;
+
+                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "DeviceAllow")) {
+                        DBusMessageIter sub, sub2;
+
+                        dbus_message_iter_recurse(iter, &sub);
+                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+                                const char *path, *rwm;
+
+                                dbus_message_iter_recurse(&sub, &sub2);
+
+                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &rwm, false) >= 0)
+                                        printf("%s=%s %s\n", name, strna(path), strna(rwm));
+
+                                dbus_message_iter_next(&sub);
+                        }
+                        return 0;
+
+                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) {
+                        DBusMessageIter sub, sub2;
+
+                        dbus_message_iter_recurse(iter, &sub);
+                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+                                const char *path;
+                                uint64_t bandwidth;
+
+                                dbus_message_iter_recurse(&sub, &sub2);
+
+                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &bandwidth, false) >= 0)
+                                        printf("%s=%s %" PRIu64 "\n", name, strna(path), bandwidth);
+
+                                dbus_message_iter_next(&sub);
+                        }
+                        return 0;
                 }
 
                 }
 
+
                 break;
         }
 
                 break;
         }
 
@@ -4667,14 +4563,6 @@ static int systemctl_help(void) {
                "  help [NAME...|PID...]           Show manual for one or more units\n"
                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
                "                                  units\n"
                "  help [NAME...|PID...]           Show manual for one or more units\n"
                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
                "                                  units\n"
-               "  get-cgroup-attr [NAME] [ATTR] ...\n"
-               "                                  Get control group attrubute\n"
-               "  set-cgroup-attr [NAME] [ATTR] [VALUE] ...\n"
-               "                                  Set control group attribute\n"
-               "  unset-cgroup-attr [NAME] [ATTR...]\n"
-               "                                  Unset control group attribute\n"
-               "  set-cgroup [NAME] [CGROUP...]   Add unit to a control group\n"
-               "  unset-cgroup [NAME] [CGROUP...] Remove unit from a control group\n"
                "  load [NAME...]                  Load one or more units\n"
                "  list-dependencies [NAME]        Recursively show units which are required\n"
                "                                  or wanted by this unit or by which this\n"
                "  load [NAME...]                  Load one or more units\n"
                "  list-dependencies [NAME]        Recursively show units which are required\n"
                "                                  or wanted by this unit or by which this\n"
@@ -5711,11 +5599,6 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
                 { "isolate",               EQUAL, 2, start_unit        },
                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
                 { "isolate",               EQUAL, 2, start_unit        },
-                { "set-cgroup",            MORE,  3, set_cgroup        },
-                { "unset-cgroup",          MORE,  3, set_cgroup        },
-                { "get-cgroup-attr",       MORE,  3, get_cgroup_attr   },
-                { "set-cgroup-attr",       MORE,  4, set_cgroup_attr   },
-                { "unset-cgroup-attr",     MORE,  3, set_cgroup        },
                 { "kill",                  MORE,  2, kill_unit         },
                 { "is-active",             MORE,  2, check_unit_active },
                 { "check",                 MORE,  2, check_unit_active },
                 { "kill",                  MORE,  2, kill_unit         },
                 { "is-active",             MORE,  2, check_unit_active },
                 { "check",                 MORE,  2, check_unit_active },
index 3a3489d6a25badf9710ebc1aeacc290ebd38e3ea..2a0ce27206ead3b0492bd29ed0b14b468b468fb5 100644 (file)
@@ -31,10 +31,10 @@ int main(int argc, char*argv[]) {
         char *path;
         char *c, *p;
 
         char *path;
         char *c, *p;
 
-        assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-a", NULL) == 0);
-        assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-a", NULL) == 0);
-        assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-b", NULL) == 0);
-        assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-c", NULL) == 0);
+        assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-a") == 0);
+        assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-a") == 0);
+        assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-b") == 0);
+        assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-c") == 0);
         assert_se(cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0) == 0);
 
         assert_se(cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0);
         assert_se(cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0) == 0);
 
         assert_se(cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0);
diff --git a/units/-.slice b/units/-.slice
new file mode 100644 (file)
index 0000000..ac82c35
--- /dev/null
@@ -0,0 +1,12 @@
+#  This file is part of systemd.
+#
+#  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.
+
+[Unit]
+Description=Root Slice
+Documentation=man:systemd.special(7)
+DefaultDependencies=no
+Before=slices.target
index cbfdba005590803cee5269ab682a408747be5bbf..a29310c047bbe800927ee9e033c857e2bc92225e 100644 (file)
@@ -8,5 +8,5 @@
 [Unit]
 Description=Slices
 Documentation=man:systemd.special(7)
 [Unit]
 Description=Slices
 Documentation=man:systemd.special(7)
-Wants=system.slice
-After=system.slice
+Wants=-.slice system.slice
+After=-.slice system.slice
index 8281fe58f67e7c511b2b4381b2b851772a4ceb63..c0e3df9d0fff2ef5a4551132b18692815228cf58 100644 (file)
@@ -10,3 +10,5 @@ Description=System Slice
 Documentation=man:systemd.special(7)
 DefaultDependencies=no
 Before=slices.target
 Documentation=man:systemd.special(7)
 DefaultDependencies=no
 Before=slices.target
+Wants=-.slice
+After=-.slice