diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2017-06-14 13:31:52 -0400 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2017-06-16 18:52:09 -0400 |
commit | 952a18bb379b00dfee0f8a8561556e707d96f931 (patch) | |
tree | 96d78ea7b5dfbff73ceee7034393331d1d900de2 | |
parent | a2c5a0f3e0f005899fd6de214ff0525b7415cb8a (diff) |
nspawn: Add a special "INHERIT" cgroup mode
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | src/basic/cgroup-util.h | 1 | ||||
-rw-r--r-- | src/nspawn/nspawn-cgroup.c | 116 | ||||
-rw-r--r-- | src/nspawn/nspawn.c | 16 |
4 files changed, 126 insertions, 9 deletions
diff --git a/Makefile.am b/Makefile.am index 35ec60f736..4f1d729a74 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3113,6 +3113,7 @@ systemd_nspawn_CFLAGS = \ $(AM_CFLAGS) \ $(ACL_CFLAGS) \ $(BLKID_CFLAGS) \ + $(MOUNT_CFLAGS) \ $(SECCOMP_CFLAGS) \ $(SELINUX_CFLAGS) @@ -3120,6 +3121,7 @@ systemd_nspawn_LDADD = \ libsystemd-shared.la \ $(ACL_LIBS) \ $(BLKID_LIBS) \ + $(MOUNT_LIBS) \ $(SECCOMP_LIBS) \ $(SELINUX_LIBS) diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index 0e5b41103e..3406e0b4fb 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -118,6 +118,7 @@ static inline bool CGROUP_BLKIO_WEIGHT_IS_OK(uint64_t x) { #define DEFAULT_USER_TASKS_MAX_PERCENTAGE 33U /* 33% of PIDs, 10813 on default settings */ typedef enum CGroupUnified { + CGROUP_UNIFIED_INHERIT = -2, /* special case only used by nspawn */ CGROUP_UNIFIED_UNKNOWN = -1, CGROUP_UNIFIED_NONE = 0, /* Both systemd and controllers on legacy */ CGROUP_UNIFIED_SYSTEMD = 1, /* Only systemd on unified */ diff --git a/src/nspawn/nspawn-cgroup.c b/src/nspawn/nspawn-cgroup.c index dafeb4a1ce..2229f4b42a 100644 --- a/src/nspawn/nspawn-cgroup.c +++ b/src/nspawn/nspawn-cgroup.c @@ -18,8 +18,11 @@ ***/ #include <sys/mount.h> +#include <libmount.h> #include "alloc-util.h" +#include "dirent-util.h" +#include "escape.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" @@ -263,13 +266,24 @@ int cgroup_setup(pid_t pid, CGroupUnified outer_cgver, CGroupUnified inner_cgver _cleanup_set_free_ Set *peers = NULL; int r; - if ((outer_cgver >= CGROUP_UNIFIED_SYSTEMD) != (inner_cgver >= CGROUP_UNIFIED_SYSTEMD)) { + if (outer_cgver == CGROUP_UNIFIED_UNKNOWN && inner_cgver != CGROUP_UNIFIED_INHERIT) { + log_error("Specifying a cgroup version is only supported when running on a systemd host"); + return -EINVAL; + } + + if ((inner_cgver != CGROUP_UNIFIED_INHERIT) && + ((outer_cgver >= CGROUP_UNIFIED_SYSTEMD) != (inner_cgver >= CGROUP_UNIFIED_SYSTEMD))) { /* sync the name=systemd hierarchy with the unified hierarchy */ r = sync_cgroup(pid, outer_cgver, inner_cgver, uid_shift); if (r < 0) return r; } + /* The rest applies only to the unified hierarchy (which if is in use, the setup is known), or the systemd + * hierarchy. */ + if (outer_cgver == CGROUP_UNIFIED_UNKNOWN) + return 0; + r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup); if (r < 0) return log_error_errno(r, "Failed to get host cgroup of the container: %m"); @@ -312,6 +326,104 @@ int cgroup_setup(pid_t pid, CGroupUnified outer_cgver, CGroupUnified inner_cgver /********************************************************************/ +static int cgroup_decide_mounts_inherit(CGMounts *ret_mounts) { + _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; + _cleanup_(cgroup_free_mounts) CGMounts mounts = {}; + int r; + + proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); + if (!proc_self_mountinfo) + return -errno; + + for (;;) { + _cleanup_free_ char *escmountpoint = NULL, *mountpoint = NULL, *fstype = NULL, *superopts = NULL, *fsopts = NULL; + char *name; + CGMountType type; + int k; + + k = fscanf(proc_self_mountinfo, + "%*s " /* (1) mount id */ + "%*s " /* (2) parent id */ + "%*s " /* (3) major:minor */ + "%*s " /* (4) root */ + "%ms " /* (5) mount point */ + "%*s" /* (6) per-mount options */ + "%*[^-]" /* (7) optional fields */ + "- " /* (8) separator */ + "%ms " /* (9) file system type */ + "%*s" /* (10) mount source */ + "%ms" /* (11) per-superblock options */ + "%*[^\n]", /* some rubbish at the end */ + &escmountpoint, + &fstype, + &superopts + ); + if (k != 3) { + if (k == EOF) + break; + + continue; + } + + r = cunescape(escmountpoint, UNESCAPE_RELAX, &mountpoint); + if (r < 0) + return r; + + name = path_startswith(mountpoint, "/sys/fs/cgroup"); + if (!name) + continue; + + if (!filename_is_valid(name) && !isempty(name)) + continue; + + if (streq(fstype, "tmpfs")) + type = CGMOUNT_TMPFS; + else if(streq(fstype, "cgroup")) + type = CGMOUNT_CGROUP1; + else if (streq(fstype, "cgroup2")) + type = CGMOUNT_CGROUP2; + else + continue; + + r = mnt_split_optstr(superopts, NULL, NULL, &fsopts, 0, 0); + if (r < 0) + return r; + + if (!cgmount_add(&mounts, type, fsopts, name)) { + return -ENOMEM; + } + + if (type == CGMOUNT_TMPFS) { + _cleanup_closedir_ DIR *dir; + struct dirent *entry; + + dir = opendir(mountpoint); + if (!dir) + return log_error_errno(errno, "Failed to open directory %s: %m", mountpoint); + + FOREACH_DIRENT(entry, dir, break) { + _cleanup_free_ char *target = NULL; + r = dirent_ensure_type(dir, entry); + if (r < 0) + return r; + if (entry->d_type != DT_LNK) + continue; + r = readlinkat_malloc(dirfd(dir), entry->d_name, &target); + if (r < 0) + return r; + if (!cgmount_add(&mounts, CGMOUNT_SYMLINK, target, entry->d_name)) + return -ENOMEM; + } + } + } + + *ret_mounts = mounts; + mounts.mounts = NULL; + mounts.n = 0; + + return 0; +} + /* Retrieve a list of cgroup v1 hierarchies. */ static int get_v1_hierarchies(Set *subsystems) { _cleanup_fclose_ FILE *f = NULL; @@ -515,6 +627,8 @@ int cgroup_decide_mounts( CGroupUnified outer_cgver, CGroupUnified inner_cgver, bool use_cgns) { switch (inner_cgver) { + case CGROUP_UNIFIED_INHERIT: + return cgroup_decide_mounts_inherit(ret_mounts); case CGROUP_UNIFIED_NONE: case CGROUP_UNIFIED_SYSTEMD: if (use_cgns) diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 94c7eea9b7..3a39b4a6f5 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -327,8 +327,12 @@ static int pick_cgroup_version(const char *directory, CGroupUnified outer) { * the container doesn't have a new enough systemd (detected * by checking libsystemd-shared). */ switch (outer) { + default: + case CGROUP_UNIFIED_INHERIT: + assert_not_reached("Invalid host cgroup version"); + return -EINVAL; case CGROUP_UNIFIED_UNKNOWN: - assert_not_reached("Unknown host cgroup version"); + arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_INHERIT; break; case CGROUP_UNIFIED_NONE: /* cgroup v1-sd */ arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_NONE; @@ -4058,6 +4062,9 @@ int main(int argc, char *argv[]) { log_parse_environment(); log_open(); cg_unified_flush(); + r = cg_version(&outer_cgver); + if (r < 0) + outer_cgver = CGROUP_UNIFIED_UNKNOWN; /* Make sure rename_process() in the stub init process can work */ saved_argv = argv; @@ -4072,13 +4079,6 @@ int main(int argc, char *argv[]) { r = -EPERM; goto finish; } - - r = cg_version(&outer_cgver); - if (r < 0) { - log_error_errno(r, "Failed to determine whether the unified cgroups hierarchy is used: %m"); - goto finish; - } - r = determine_names(); if (r < 0) goto finish; |