if (r < 0)
return log_error_errno(r, "Kernel upload of egress BPF program failed: %m");
- r = bpf_program_cgroup_attach(u->ip_bpf_egress, BPF_CGROUP_INET_EGRESS, path, cc->delegate ? BPF_F_ALLOW_OVERRIDE : 0);
+ r = bpf_program_cgroup_attach(u->ip_bpf_egress, BPF_CGROUP_INET_EGRESS, path, unit_cgroup_delegate(u) ? BPF_F_ALLOW_OVERRIDE : 0);
if (r < 0)
return log_error_errno(r, "Attaching egress BPF program to cgroup %s failed: %m", path);
} else {
if (r < 0)
return log_error_errno(r, "Kernel upload of ingress BPF program failed: %m");
- r = bpf_program_cgroup_attach(u->ip_bpf_ingress, BPF_CGROUP_INET_INGRESS, path, cc->delegate ? BPF_F_ALLOW_OVERRIDE : 0);
+ r = bpf_program_cgroup_attach(u->ip_bpf_ingress, BPF_CGROUP_INET_INGRESS, path, unit_cgroup_delegate(u) ? BPF_F_ALLOW_OVERRIDE : 0);
if (r < 0)
return log_error_errno(r, "Attaching ingress BPF program to cgroup %s failed: %m", path);
} else {
*
* Note that on the unified hierarchy it is safe to delegate controllers to unprivileged services. */
- if (u->type == UNIT_SLICE)
- return 0;
-
- c = unit_get_cgroup_context(u);
- if (!c)
- return 0;
-
- if (!c->delegate)
+ if (!unit_cgroup_delegate(u))
return 0;
if (cg_all_unified() <= 0) {
return 0;
}
+ assert_se(c = unit_get_cgroup_context(u));
return c->delegate_controllers;
}
u->cgroup_enabled_mask = enable_mask;
u->cgroup_bpf_state = needs_bpf ? UNIT_CGROUP_BPF_ON : UNIT_CGROUP_BPF_OFF;
- if (u->type != UNIT_SLICE && !c->delegate) {
+ if (u->type != UNIT_SLICE && !unit_cgroup_delegate(u)) {
/* Then, possibly move things over, but not if
* subgroups may contain processes, which is the case
}
}
+bool unit_cgroup_delegate(Unit *u) {
+ CGroupContext *c;
+
+ assert(u);
+
+ if (!UNIT_VTABLE(u)->can_delegate)
+ return false;
+
+ c = unit_get_cgroup_context(u);
+ if (!c)
+ return false;
+
+ return c->delegate;
+}
+
void manager_invalidate_startup_units(Manager *m) {
Iterator i;
Unit *u;
const char* cgroup_device_policy_to_string(CGroupDevicePolicy i) _const_;
CGroupDevicePolicy cgroup_device_policy_from_string(const char *s) _pure_;
+
+bool unit_cgroup_delegate(Unit *u);
if (streq(name, "Delegate")) {
int b;
+ if (!UNIT_VTABLE(u)->can_delegate)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delegation not available for unit type");
+
r = sd_bus_message_read(message, "b", &b);
if (r < 0)
return r;
} else if (streq(name, "DelegateControllers")) {
CGroupMask mask = 0;
+ if (!UNIT_VTABLE(u)->can_delegate)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delegation not available for unit type");
+
r = sd_bus_message_enter_container(message, 'a', "s");
if (r < 0)
return r;
.private_section = "Scope",
.can_transient = true,
+ .can_delegate = true,
.init = scope_init,
.load = scope_load,
"Install\0",
.private_section = "Service",
+ .can_transient = true,
+ .can_delegate = true,
+
.init = service_init,
.done = service_done,
.load = service_load,
.get_timeout = service_get_timeout,
.needs_console = service_needs_console,
- .can_transient = true,
.status_message_formats = {
.starting_stopping = {
} else if (r > 0) {
- /* FIXME: For now, on the legacy hierarchy, we
- * will not wait for the cgroup members to die
- * if we are running in a container or if this
- * is a delegation unit, simply because cgroup
- * notification is unreliable in these
- * cases. It doesn't work at all in
- * containers, and outside of containers it
- * can be confused easily by left-over
- * directories in the cgroup — which however
- * should not exist in non-delegated units. On
- * the unified hierarchy that's different,
- * there we get proper events. Hence rely on
- * them. */
+ /* FIXME: For now, on the legacy hierarchy, we will not wait for the cgroup members to die if
+ * we are running in a container or if this is a delegation unit, simply because cgroup
+ * notification is unreliable in these cases. It doesn't work at all in containers, and outside
+ * of containers it can be confused easily by left-over directories in the cgroup — which
+ * however should not exist in non-delegated units. On the unified hierarchy that's different,
+ * there we get proper events. Hence rely on them. */
if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) > 0 ||
- (detect_container() == 0 && !UNIT_CGROUP_BOOL(u, delegate)))
+ (detect_container() == 0 && !unit_cgroup_delegate(u)))
wait_for_exit = true;
if (send_sighup) {
assert(p);
p->cgroup_path = u->cgroup_path;
- SET_FLAG(p->flags, EXEC_CGROUP_DELEGATE, UNIT_CGROUP_BOOL(u, delegate));
+ SET_FLAG(p->flags, EXEC_CGROUP_DELEGATE, unit_cgroup_delegate(u));
}
int unit_fork_helper_process(Unit *u, const char *name, pid_t *ret) {
/* True if transient units of this type are OK */
bool can_transient:1;
+ /* True if cgroup delegation is permissible */
+ bool can_delegate:1;
+
/* True if queued jobs of this type should be GC'ed if no other job needs them anymore */
bool gc_jobs:1;
};