nspawn-cgroup.c revision 34829a324b1ffc6cb8405223329a9c55cd8de0ee
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek/***
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek This file is part of systemd.
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek Copyright 2015 Lennart Poettering
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek systemd is free software; you can redistribute it and/or modify it
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek under the terms of the GNU Lesser General Public License as published by
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek the Free Software Foundation; either version 2.1 of the License, or
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek (at your option) any later version.
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek systemd is distributed in the hope that it will be useful, but
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek WITHOUT ANY WARRANTY; without even the implied warranty of
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek Lesser General Public License for more details.
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek You should have received a copy of the GNU Lesser General Public License
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek along with systemd; If not, see <http://www.gnu.org/licenses/>.
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek***/
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek#include <sys/mount.h>
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include "util.h"
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering#include "strv.h"
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering#include "mkdir.h"
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek#include "fileio.h"
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek#include "cgroup-util.h"
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering
3f0b2f0f452e94444e4fb7b62030ea05738bb1b6Zbigniew Jędrzejewski-Szmek#include "nspawn.h"
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek#include "nspawn-cgroup.h"
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering
cab6235f748e365198a7939f23c87ab3b8f59b2eLennart Poetteringint chown_cgroup(pid_t pid, uid_t uid_shift) {
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering _cleanup_free_ char *path = NULL, *fs = NULL;
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek _cleanup_close_ int fd = -1;
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek const char *fn;
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering int r;
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek r = cg_pid_get_path(NULL, pid, &path);
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering if (r < 0)
cab6235f748e365198a7939f23c87ab3b8f59b2eLennart Poettering return log_error_errno(r, "Failed to get container cgroup path: %m");
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, path, NULL, &fs);
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek if (r < 0)
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering return log_error_errno(r, "Failed to get file system path for container cgroup: %m");
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek fd = open(fs, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering if (fd < 0)
cab6235f748e365198a7939f23c87ab3b8f59b2eLennart Poettering return log_error_errno(errno, "Failed to open %s: %m", fs);
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek FOREACH_STRING(fn,
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek ".",
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek "tasks",
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek "notify_on_release",
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek "cgroup.procs",
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek "cgroup.clone_children",
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering "cgroup.controllers",
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering "cgroup.subtree_control",
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering "cgroup.populated")
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering if (fchownat(fd, fn, uid_shift, uid_shift, 0) < 0)
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering "Failed to chown() cgroup file %s, ignoring: %m", fn);
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering return 0;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering}
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmekint sync_cgroup(pid_t pid, bool unified_requested) {
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek _cleanup_free_ char *cgroup = NULL;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering char tree[] = "/tmp/unifiedXXXXXX", pid_string[DECIMAL_STR_MAX(pid) + 1];
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering bool undo_mount = false;
3f0b2f0f452e94444e4fb7b62030ea05738bb1b6Zbigniew Jędrzejewski-Szmek const char *fn;
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering int unified, r;
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering unified = cg_unified();
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering if (unified < 0)
3f0b2f0f452e94444e4fb7b62030ea05738bb1b6Zbigniew Jędrzejewski-Szmek return log_error_errno(unified, "Failed to determine whether the unified hierachy is used: %m");
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering if ((unified > 0) == unified_requested)
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering return 0;
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering /* When the host uses the legacy cgroup setup, but the
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering * container shall use the unified hierarchy, let's make sure
3f0b2f0f452e94444e4fb7b62030ea05738bb1b6Zbigniew Jędrzejewski-Szmek * we copy the path from the name=systemd hierarchy into the
3f0b2f0f452e94444e4fb7b62030ea05738bb1b6Zbigniew Jędrzejewski-Szmek * unified hierarchy. Similar for the reverse situation. */
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup);
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering if (r < 0)
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering return log_error_errno(r, "Failed to get control group of " PID_FMT ": %m", pid);
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering /* In order to access the unified hierarchy we need to mount it */
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering if (!mkdtemp(tree))
3f0b2f0f452e94444e4fb7b62030ea05738bb1b6Zbigniew Jędrzejewski-Szmek return log_error_errno(errno, "Failed to generate temporary mount point for unified hierarchy: %m");
cab6235f748e365198a7939f23c87ab3b8f59b2eLennart Poettering
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek if (unified)
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek r = mount("cgroup", tree, "cgroup", MS_NOSUID|MS_NOEXEC|MS_NODEV, "none,name=systemd,xattr");
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek else
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek r = mount("cgroup", tree, "cgroup", MS_NOSUID|MS_NOEXEC|MS_NODEV, "__DEVEL__sane_behavior");
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek if (r < 0) {
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek r = log_error_errno(errno, "Failed to mount unified hierarchy: %m");
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek goto finish;
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek }
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering undo_mount = true;
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek fn = strjoina(tree, cgroup, "/cgroup.procs");
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek (void) mkdir_parents(fn, 0755);
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
6aaa8c2f783cd1b3ac27c5ce40625d032e7e3d71Zbigniew Jędrzejewski-Szmek sprintf(pid_string, PID_FMT, pid);
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek r = write_string_file(fn, pid_string, 0);
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek if (r < 0)
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek log_error_errno(r, "Failed to move process: %m");
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmekfinish:
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek if (undo_mount)
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek (void) umount(tree);
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
79413b673b45adc98dfeaec882bbdda2343cb2f9Lennart Poettering (void) rmdir(tree);
3f0b2f0f452e94444e4fb7b62030ea05738bb1b6Zbigniew Jędrzejewski-Szmek return r;
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek}
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmekint create_subcgroup(pid_t pid, bool unified_requested) {
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek _cleanup_free_ char *cgroup = NULL;
6aaa8c2f783cd1b3ac27c5ce40625d032e7e3d71Zbigniew Jędrzejewski-Szmek const char *child;
6aaa8c2f783cd1b3ac27c5ce40625d032e7e3d71Zbigniew Jędrzejewski-Szmek int unified, r;
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek CGroupMask supported;
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek /* In the unified hierarchy inner nodes may only only contain
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek * subgroups, but not processes. Hence, if we running in the
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering * unified hierarchy and the container does the same, and we
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek * did not create a scope unit for the container move us and
19f6d710772305610b928bc2678b9d77fe11e770Lennart Poettering * the container into two separate subcgroups. */
7584d236eac91f9b7128b1eb08bddf18be2bce9fZbigniew Jędrzejewski-Szmek
if (!unified_requested)
return 0;
unified = cg_unified();
if (unified < 0)
return log_error_errno(unified, "Failed to determine whether the unified hierachy is used: %m");
if (unified == 0)
return 0;
r = cg_mask_supported(&supported);
if (r < 0)
return log_error_errno(r, "Failed to determine supported controllers: %m");
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup);
if (r < 0)
return log_error_errno(r, "Failed to get our control group: %m");
child = strjoina(cgroup, "/payload");
r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, child, pid);
if (r < 0)
return log_error_errno(r, "Failed to create %s subcgroup: %m", child);
child = strjoina(cgroup, "/supervisor");
r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, child, 0);
if (r < 0)
return log_error_errno(r, "Failed to create %s subcgroup: %m", child);
/* Try to enable as many controllers as possible for the new payload. */
(void) cg_enable_everywhere(supported, supported, cgroup);
return 0;
}