core: general cgroup rework

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=).
This commit is contained in:
Lennart Poettering
2013-06-27 04:17:34 +02:00
parent abb26902e4
commit 4ad490007b
57 changed files with 1720 additions and 2880 deletions
+7 -4
View File
@@ -36,15 +36,18 @@
#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;
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;
r = mkdir_parents_label(fs, 0755);
r = mkdir_parents_prefix("/sys/fs/cgroup", fs, 0755);
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);
r = cg_create(controller, path, NULL);
r = cg_create(controller, path);
if (r < 0)
return r;
-1
View File
@@ -241,7 +241,6 @@ static int show_extra_pids(const char *controller, const char *path, const char
unsigned i, j;
int r;
assert(controller);
assert(path);
if (n_pids <= 0)
+163 -106
View File
@@ -132,7 +132,7 @@ int cg_read_subgroup(DIR *d, char **fn) {
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;
@@ -140,34 +140,6 @@ int cg_rmdir(const char *controller, const char *path, bool honour_sticky) {
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;
@@ -298,7 +270,7 @@ int cg_kill_recursive(const char *controller, const char *path, int sig, bool si
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;
}
@@ -407,7 +379,14 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char
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;
@@ -448,7 +427,7 @@ int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto,
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;
}
@@ -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) {
char *p;
bool is_sticky;
assert(path);
assert(sb);
assert(ftwbuf);
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;
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;
}
@@ -611,28 +566,8 @@ int cg_trim(const char *controller, const char *path, bool 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;
@@ -699,15 +634,14 @@ int cg_set_task_access(
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);
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)
@@ -717,28 +651,6 @@ int cg_set_task_access(
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;
@@ -1688,3 +1600,148 @@ int cg_slice_to_path(const char *unit, char **ret) {
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;
}
+21 -3
View File
@@ -28,6 +28,15 @@
#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:
*
@@ -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_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_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_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_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);
@@ -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);
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);
-1
View File
@@ -24,7 +24,6 @@
#include "util.h"
#include "strv.h"
int write_string_to_file(FILE *f, const char *line) {
errno = 0;
fputs(line, f);
+45 -29
View File
@@ -26,15 +26,16 @@
#include <stdlib.h>
#include <stdio.h>
#include "mkdir.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);
}
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)
@@ -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) {
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) {
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;
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;
int r;
assert(path);
if (prefix && !path_startswith(path, prefix))
return -ENOTDIR;
/* return immediately if directory exists */
e = strrchr(path, '/');
if (!e)
return -EINVAL;
if (e == path)
return 0;
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 (;;) {
int r;
char *t;
char t[strlen(path) + 1];
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;
t = strndup(path, e - path);
if (!t)
return -ENOMEM;
memcpy(t, path, e - path);
t[e-path] = 0;
if (prefix && path_startswith(prefix, t))
continue;
r = label_mkdir(t, mode, apply);
free(t);
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) {
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 */
r = makedir_parents(path, mode, apply);
r = mkdir_parents_internal(prefix, path, mode, apply);
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) {
return makedir_p(path, mode, false);
return mkdir_p_internal(NULL, path, mode, false);
}
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);
}
+8
View File
@@ -22,11 +22,19 @@
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_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_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_prefix(const char *prefix, const char *path, mode_t mode);
#endif