2 This file is part of systemd.
4 Copyright 2015 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include <sys/mount.h>
22 #include "alloc-util.h"
23 #include "cgroup-util.h"
27 #include "nspawn-cgroup.h"
28 #include "string-util.h"
32 int chown_cgroup(pid_t pid
, uid_t uid_shift
) {
33 _cleanup_free_
char *path
= NULL
, *fs
= NULL
;
34 _cleanup_close_
int fd
= -1;
38 r
= cg_pid_get_path(NULL
, pid
, &path
);
40 return log_error_errno(r
, "Failed to get container cgroup path: %m");
42 r
= cg_get_path(SYSTEMD_CGROUP_CONTROLLER
, path
, NULL
, &fs
);
44 return log_error_errno(r
, "Failed to get file system path for container cgroup: %m");
46 fd
= open(fs
, O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
48 return log_error_errno(errno
, "Failed to open %s: %m", fs
);
56 "cgroup.clone_children",
58 "cgroup.subtree_control",
60 if (fchownat(fd
, fn
, uid_shift
, uid_shift
, 0) < 0)
61 log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_WARNING
, errno
,
62 "Failed to chown() cgroup file %s, ignoring: %m", fn
);
67 int sync_cgroup(pid_t pid
, bool unified_requested
) {
68 _cleanup_free_
char *cgroup
= NULL
;
69 char tree
[] = "/tmp/unifiedXXXXXX", pid_string
[DECIMAL_STR_MAX(pid
) + 1];
70 bool undo_mount
= false;
74 unified
= cg_unified();
76 return log_error_errno(unified
, "Failed to determine whether the unified hierachy is used: %m");
78 if ((unified
> 0) == unified_requested
)
81 /* When the host uses the legacy cgroup setup, but the
82 * container shall use the unified hierarchy, let's make sure
83 * we copy the path from the name=systemd hierarchy into the
84 * unified hierarchy. Similar for the reverse situation. */
86 r
= cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER
, pid
, &cgroup
);
88 return log_error_errno(r
, "Failed to get control group of " PID_FMT
": %m", pid
);
90 /* In order to access the unified hierarchy we need to mount it */
92 return log_error_errno(errno
, "Failed to generate temporary mount point for unified hierarchy: %m");
95 r
= mount("cgroup", tree
, "cgroup", MS_NOSUID
|MS_NOEXEC
|MS_NODEV
, "none,name=systemd,xattr");
97 r
= mount("cgroup", tree
, "cgroup", MS_NOSUID
|MS_NOEXEC
|MS_NODEV
, "__DEVEL__sane_behavior");
99 r
= log_error_errno(errno
, "Failed to mount unified hierarchy: %m");
105 fn
= strjoina(tree
, cgroup
, "/cgroup.procs");
106 (void) mkdir_parents(fn
, 0755);
108 sprintf(pid_string
, PID_FMT
, pid
);
109 r
= write_string_file(fn
, pid_string
, 0);
111 log_error_errno(r
, "Failed to move process: %m");
121 int create_subcgroup(pid_t pid
, bool unified_requested
) {
122 _cleanup_free_
char *cgroup
= NULL
;
125 CGroupMask supported
;
127 /* In the unified hierarchy inner nodes may only only contain
128 * subgroups, but not processes. Hence, if we running in the
129 * unified hierarchy and the container does the same, and we
130 * did not create a scope unit for the container move us and
131 * the container into two separate subcgroups. */
133 if (!unified_requested
)
136 unified
= cg_unified();
138 return log_error_errno(unified
, "Failed to determine whether the unified hierachy is used: %m");
142 r
= cg_mask_supported(&supported
);
144 return log_error_errno(r
, "Failed to determine supported controllers: %m");
146 r
= cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER
, 0, &cgroup
);
148 return log_error_errno(r
, "Failed to get our control group: %m");
150 child
= strjoina(cgroup
, "/payload");
151 r
= cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER
, child
, pid
);
153 return log_error_errno(r
, "Failed to create %s subcgroup: %m", child
);
155 child
= strjoina(cgroup
, "/supervisor");
156 r
= cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER
, child
, 0);
158 return log_error_errno(r
, "Failed to create %s subcgroup: %m", child
);
160 /* Try to enable as many controllers as possible for the new payload. */
161 (void) cg_enable_everywhere(supported
, supported
, cgroup
);