summaryrefslogtreecommitdiffstats
path: root/src/shared/cgroup-setup.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/shared/cgroup-setup.c122
1 files changed, 65 insertions, 57 deletions
diff --git a/src/shared/cgroup-setup.c b/src/shared/cgroup-setup.c
index 934a16e..093b6d0 100644
--- a/src/shared/cgroup-setup.c
+++ b/src/shared/cgroup-setup.c
@@ -51,7 +51,7 @@ static int cg_any_controller_used_for_v1(void) {
continue;
const char *p = *line;
- r = extract_many_words(&p, NULL, 0, &name, &hierarchy_id, &num, &enabled, NULL);
+ r = extract_many_words(&p, NULL, 0, &name, &hierarchy_id, &num, &enabled);
if (r < 0)
return log_debug_errno(r, "Error parsing /proc/cgroups line, ignoring: %m");
else if (r < 4) {
@@ -81,9 +81,6 @@ static int cg_any_controller_used_for_v1(void) {
bool cg_is_unified_wanted(void) {
static thread_local int wanted = -1;
- bool b;
- const bool is_default = DEFAULT_HIERARCHY == CGROUP_UNIFIED_ALL;
- _cleanup_free_ char *c = NULL;
int r;
/* If we have a cached value, return that. */
@@ -96,21 +93,20 @@ bool cg_is_unified_wanted(void) {
return (wanted = r >= CGROUP_UNIFIED_ALL);
/* If we were explicitly passed systemd.unified_cgroup_hierarchy, respect that. */
+ bool b;
r = proc_cmdline_get_bool("systemd.unified_cgroup_hierarchy", /* flags = */ 0, &b);
if (r > 0)
return (wanted = b);
/* If we passed cgroup_no_v1=all with no other instructions, it seems highly unlikely that we want to
* use hybrid or legacy hierarchy. */
+ _cleanup_free_ char *c = NULL;
r = proc_cmdline_get_key("cgroup_no_v1", 0, &c);
if (r > 0 && streq_ptr(c, "all"))
return (wanted = true);
/* If any controller is in use as v1, don't use unified. */
- if (cg_any_controller_used_for_v1() > 0)
- return (wanted = false);
-
- return (wanted = is_default);
+ return (wanted = (cg_any_controller_used_for_v1() <= 0));
}
bool cg_is_legacy_wanted(void) {
@@ -132,10 +128,6 @@ bool cg_is_legacy_wanted(void) {
bool cg_is_hybrid_wanted(void) {
static thread_local int wanted = -1;
int r;
- bool b;
- const bool is_default = DEFAULT_HIERARCHY >= CGROUP_UNIFIED_SYSTEMD;
- /* We default to true if the default is "hybrid", obviously, but also when the default is "unified",
- * because if we get called, it means that unified hierarchy was not mounted. */
/* If we have a cached value, return that. */
if (wanted >= 0)
@@ -146,12 +138,33 @@ bool cg_is_hybrid_wanted(void) {
return (wanted = false);
/* Otherwise, let's see what the kernel command line has to say. Since checking is expensive, cache
- * a non-error result. */
+ * a non-error result.
+ * The meaning of the kernel option is reversed wrt. to the return value of this function, hence the
+ * negation. */
+ bool b;
r = proc_cmdline_get_bool("systemd.legacy_systemd_cgroup_controller", /* flags = */ 0, &b);
+ if (r > 0)
+ return (wanted = !b);
- /* The meaning of the kernel option is reversed wrt. to the return value of this function, hence the
- * negation. */
- return (wanted = r > 0 ? !b : is_default);
+ /* The default hierarchy is "unified". But if this is reached, it means that unified hierarchy was
+ * not mounted, so return true too. */
+ return (wanted = true);
+}
+
+bool cg_is_legacy_force_enabled(void) {
+ bool force;
+
+ if (!cg_is_legacy_wanted())
+ return false;
+
+ /* If in container, we have to follow host's cgroup hierarchy. */
+ if (detect_container() > 0)
+ return true;
+
+ if (proc_cmdline_get_bool("SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE", /* flags = */ 0, &force) < 0)
+ return false;
+
+ return force;
}
int cg_weight_parse(const char *s, uint64_t *ret) {
@@ -371,6 +384,20 @@ int cg_attach(const char *controller, const char *path, pid_t pid) {
return 0;
}
+int cg_fd_attach(int fd, pid_t pid) {
+ char c[DECIMAL_STR_MAX(pid_t) + 2];
+
+ assert(fd >= 0);
+ assert(pid >= 0);
+
+ if (pid == 0)
+ pid = getpid_cached();
+
+ xsprintf(c, PID_FMT "\n", pid);
+
+ return write_string_file_at(fd, "cgroup.procs", c, WRITE_STRING_FILE_DISABLE_BUFFER);
+}
+
int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
int r;
@@ -571,75 +598,56 @@ int cg_migrate(
bool done = false;
_cleanup_set_free_ Set *s = NULL;
int r, ret = 0;
- pid_t my_pid;
assert(cfrom);
assert(pfrom);
assert(cto);
assert(pto);
- s = set_new(NULL);
- if (!s)
- return -ENOMEM;
-
- my_pid = getpid_cached();
-
do {
_cleanup_fclose_ FILE *f = NULL;
- pid_t pid = 0;
+ pid_t pid;
+
done = true;
r = cg_enumerate_processes(cfrom, pfrom, &f);
- if (r < 0) {
- if (ret >= 0 && r != -ENOENT)
- return r;
-
- return ret;
- }
+ if (r < 0)
+ return RET_GATHER(ret, r);
- while ((r = cg_read_pid(f, &pid)) > 0) {
+ while ((r = cg_read_pid(f, &pid, flags)) > 0) {
+ /* Throw an error if unmappable PIDs are in output, we can't migrate those. */
+ if (pid == 0)
+ return -EREMOTE;
- /* This might do weird stuff if we aren't a
- * single-threaded program. However, we
- * luckily know we are not */
- if ((flags & CGROUP_IGNORE_SELF) && pid == my_pid)
+ /* This might do weird stuff if we aren't a single-threaded program. However, we
+ * luckily know we are. */
+ if (FLAGS_SET(flags, CGROUP_IGNORE_SELF) && pid == getpid_cached())
continue;
- if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid))
+ if (set_contains(s, PID_TO_PTR(pid)))
continue;
- /* Ignore kernel threads. Since they can only
- * exist in the root cgroup, we only check for
- * them there. */
- if (cfrom &&
- empty_or_root(pfrom) &&
+ /* Ignore kernel threads. Since they can only exist in the root cgroup, we only
+ * check for them there. */
+ if (cfrom && empty_or_root(pfrom) &&
pid_is_kernel_thread(pid) > 0)
continue;
r = cg_attach(cto, pto, pid);
if (r < 0) {
- if (ret >= 0 && r != -ESRCH)
- ret = r;
+ if (r != -ESRCH)
+ RET_GATHER(ret, r);
} else if (ret == 0)
ret = 1;
done = false;
- r = set_put(s, PID_TO_PTR(pid));
- if (r < 0) {
- if (ret >= 0)
- return r;
-
- return ret;
- }
- }
-
- if (r < 0) {
- if (ret >= 0)
- return r;
-
- return ret;
+ r = set_ensure_put(&s, /* hash_ops = */ NULL, PID_TO_PTR(pid));
+ if (r < 0)
+ return RET_GATHER(ret, r);
}
+ if (r < 0)
+ return RET_GATHER(ret, r);
} while (!done);
return ret;