diff --git a/docs/TRANSIENT-SETTINGS.md b/docs/TRANSIENT-SETTINGS.md index 652ac3d95e..3ea5116349 100644 --- a/docs/TRANSIENT-SETTINGS.md +++ b/docs/TRANSIENT-SETTINGS.md @@ -307,6 +307,7 @@ All cgroup/resource control settings are available for transient units ✓ StartupAllowedCPUs= ✓ AllowedMemoryNodes= ✓ StartupAllowedMemoryNodes= +✓ CPUSetPartition= ✓ DisableControllers= ✓ Delegate= ✓ MemoryMin= diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index 847e76f95c..5474dd788e 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -3010,6 +3010,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly ay StartupAllowedMemoryNodes = [...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly s CPUSetPartition = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly b IOAccounting = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly t IOWeight = ...; @@ -3689,6 +3691,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + @@ -4387,6 +4391,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + @@ -5294,6 +5300,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly ay StartupAllowedMemoryNodes = [...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly s CPUSetPartition = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly b IOAccounting = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly t IOWeight = ...; @@ -5989,6 +5997,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + @@ -6661,6 +6671,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + @@ -7391,6 +7403,8 @@ node /org/freedesktop/systemd1/unit/home_2emount { @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly ay StartupAllowedMemoryNodes = [...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly s CPUSetPartition = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly b IOAccounting = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly t IOWeight = ...; @@ -8010,6 +8024,8 @@ node /org/freedesktop/systemd1/unit/home_2emount { + + @@ -8590,6 +8606,8 @@ node /org/freedesktop/systemd1/unit/home_2emount { + + @@ -9453,6 +9471,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly ay StartupAllowedMemoryNodes = [...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly s CPUSetPartition = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly b IOAccounting = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly t IOWeight = ...; @@ -10054,6 +10074,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { + + @@ -10616,6 +10638,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { + + @@ -11332,6 +11356,8 @@ node /org/freedesktop/systemd1/unit/system_2eslice { @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly ay StartupAllowedMemoryNodes = [...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly s CPUSetPartition = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly b IOAccounting = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly t IOWeight = ...; @@ -11515,6 +11541,8 @@ node /org/freedesktop/systemd1/unit/system_2eslice { + + @@ -11709,6 +11737,8 @@ node /org/freedesktop/systemd1/unit/system_2eslice { + + @@ -11928,6 +11958,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope { @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly ay StartupAllowedMemoryNodes = [...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly s CPUSetPartition = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly b IOAccounting = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly t IOWeight = ...; @@ -12125,6 +12157,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope { + + @@ -12343,6 +12377,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope { + + @@ -12750,8 +12786,9 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \ RefreshOnReload, and RootMStack were added in version 260. CPUPressureThresholdUSec, CPUPressureWatch, - IOPressureThresholdUSec, and - IOPressureWatch were added in version 261. + IOPressureThresholdUSec, + IOPressureWatch, and + CPUSetPartition were added in version 261. Socket Unit Objects @@ -12824,8 +12861,9 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \ RootMStack were added in version 260. CPUPressureThresholdUSec, CPUPressureWatch, - IOPressureThresholdUSec, and - IOPressureWatch were added in version 261. + IOPressureThresholdUSec, + IOPressureWatch, and + CPUSetPartition were added in version 261. Mount Unit Objects @@ -12893,8 +12931,9 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \ RootMStack were added in version 260. CPUPressureThresholdUSec, CPUPressureWatch, - IOPressureThresholdUSec, and - IOPressureWatch were added in version 261. + IOPressureThresholdUSec, + IOPressureWatch, and + CPUSetPartition were added in version 261. Swap Unit Objects @@ -12960,8 +12999,9 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \ RootMStack were added in version 260. CPUPressureThresholdUSec, CPUPressureWatch, - IOPressureThresholdUSec, and - IOPressureWatch were added in version 261. + IOPressureThresholdUSec, + IOPressureWatch, and + CPUSetPartition were added in version 261. Slice Unit Objects @@ -12997,8 +13037,9 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \ BindNetworkInterface was added in version 260. CPUPressureThresholdUSec, CPUPressureWatch, - IOPressureThresholdUSec, and - IOPressureWatch were added in version 261. + IOPressureThresholdUSec, + IOPressureWatch, and + CPUSetPartition were added in version 261. Scope Unit Objects @@ -13032,8 +13073,9 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \ BindNetworkInterface was added in version 260. CPUPressureThresholdUSec, CPUPressureWatch, - IOPressureThresholdUSec, and - IOPressureWatch were added in version 261. + IOPressureThresholdUSec, + IOPressureWatch, and + CPUSetPartition were added in version 261. Job Objects diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index b5d559849d..fcad4b3183 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -521,6 +521,28 @@ CPUWeight=20 DisableControllers=cpu / \ + + CPUSetPartition= + + + Sets the partition type for the executed processes. Takes one + of member, root, or isolated. This setting + controls the cpuset.cpus.partition cgroup attribute. + + When set to member, the cpuset operates in normal mode. + root creates a partition root, which can further divide CPUs among child cgroups. + isolated provides full CPU isolation, useful for real-time workloads that + require dedicated CPU resources without interference from other processes. + Defaults to the kernel default, which is member. For more details about this + control group attribute, see + Control Groups v2. + + This setting requires AllowedCPUs= to also be set. + + + + + Process Accounting and Control diff --git a/src/core/cgroup.c b/src/core/cgroup.c index acf2e8147f..52d73b3747 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -178,6 +178,8 @@ void cgroup_context_init(CGroupContext *c) { .tasks_max = CGROUP_TASKS_MAX_UNSET, + .cpuset_partition = _CPUSET_PARTITION_INVALID, + .moom_swap = MANAGED_OOM_AUTO, .moom_mem_pressure = MANAGED_OOM_AUTO, .moom_preference = MANAGED_OOM_PREFERENCE_NONE, @@ -508,6 +510,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { "%sStartupAllowedCPUs: %s\n" "%sAllowedMemoryNodes: %s\n" "%sStartupAllowedMemoryNodes: %s\n" + "%sCPUSetPartition: %s\n" "%sIOWeight: %" PRIu64 "\n" "%sStartupIOWeight: %" PRIu64 "\n" "%sMemoryMin: %" PRIu64 "%s\n" @@ -546,6 +549,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { prefix, strempty(startup_cpuset_cpus), prefix, strempty(cpuset_mems), prefix, strempty(startup_cpuset_mems), + prefix, strna(cpuset_partition_to_string(c->cpuset_partition)), prefix, c->io_weight, prefix, c->startup_io_weight, prefix, c->memory_min, format_cgroup_memory_limit_comparison(u, "MemoryMin", cda, sizeof(cda)), @@ -1132,6 +1136,53 @@ static void cgroup_apply_cpuset(Unit *u, const CPUSet *cpus, const char *name) { (void) set_attribute_and_warn(u, name, buf); } +static int cgroup_cpuset_partition_invalid(const char *partition) { + _cleanup_free_ char *part_str = NULL, *invalid = NULL; + int r; + + assert(partition); + + /* An invalid line looks like invalid () */ + r = extract_many_words(&partition, /* separators= */ NULL, /* flags= */ 0, &part_str, &invalid); + if (r < 0) + return r; + if (r < 2) + return false; + + return streq_ptr(invalid, "invalid"); +} + +static void cgroup_apply_cpuset_partition(Unit *u, const char *name, const char *partition) { + _cleanup_free_ char *buf = NULL; + CGroupRuntime *crt; + int r; + + assert(u); + assert(name); + assert(partition); + + if (set_attribute_and_warn(u, name, partition) < 0) + return; + + /* We are writing and then reading back, crt is already checked while writing */ + crt = ASSERT_PTR(unit_get_cgroup_runtime(u)); + + r = cg_get_attribute(crt->cgroup_path, name, &buf); + if (r < 0) { + log_unit_full_errno(u, LOG_LEVEL_CGROUP_WRITE(r), r, "Failed to read back '%s' attribute on '%s' as '%.*s': %m", + name, empty_to_root(crt->cgroup_path), (int) strcspn(partition, NEWLINE), partition); + return; + } + + r = cgroup_cpuset_partition_invalid(buf); + if (r < 0) + log_unit_full_errno(u, LOG_LEVEL_CGROUP_WRITE(r), r, "Failed to read back '%s' attribute on '%s' as '%.*s': %m", + name, empty_to_root(crt->cgroup_path), (int) strcspn(partition, NEWLINE), partition); + else if (r) + log_unit_warning(u, "Failed to set '%s' attribute on '%s' to '%.*s': %s", + name, empty_to_root(crt->cgroup_path), (int) strcspn(partition, NEWLINE), partition, buf); +} + static bool cgroup_context_has_io_config(CGroupContext *c) { assert(c); @@ -1464,6 +1515,9 @@ static void cgroup_context_apply( if ((apply_mask & CGROUP_MASK_CPUSET) && !is_local_root) { cgroup_apply_cpuset(u, cgroup_context_allowed_cpus(c, state), "cpuset.cpus"); cgroup_apply_cpuset(u, cgroup_context_allowed_mems(c, state), "cpuset.mems"); + + if (c->cpuset_partition >= 0) + cgroup_apply_cpuset_partition(u, "cpuset.cpus.partition", cpuset_partition_to_string(c->cpuset_partition)); } /* The 'io' controller attributes are not exported on the host's root cgroup (being a pure cgroup v2 @@ -4582,6 +4636,14 @@ static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = DEFINE_STRING_TABLE_LOOKUP(cgroup_device_policy, CGroupDevicePolicy); +static const char* const cpuset_partition_table[_CPUSET_PARTITION_MAX] = { + [CPUSET_PARTITION_MEMBER] = "member", + [CPUSET_PARTITION_ROOT] = "root", + [CPUSET_PARTITION_ISOLATED] = "isolated", +}; + +DEFINE_STRING_TABLE_LOOKUP(cpuset_partition, CPUSetPartition); + static const char* const cgroup_pressure_watch_table[_CGROUP_PRESSURE_WATCH_MAX] = { [CGROUP_PRESSURE_WATCH_NO] = "no", [CGROUP_PRESSURE_WATCH_YES] = "yes", diff --git a/src/core/cgroup.h b/src/core/cgroup.h index d9a6ded110..b7213d8d59 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -47,6 +47,14 @@ typedef enum FreezerAction { _FREEZER_ACTION_INVALID = -EINVAL, } FreezerAction; +typedef enum CPUSetPartition { + CPUSET_PARTITION_MEMBER, + CPUSET_PARTITION_ROOT, + CPUSET_PARTITION_ISOLATED, + _CPUSET_PARTITION_MAX, + _CPUSET_PARTITION_INVALID = -EINVAL, +} CPUSetPartition; + typedef enum CGroupDevicePermissions { /* We reuse the same bit meanings the kernel's BPF_DEVCG_ACC_xyz definitions use */ CGROUP_DEVICE_MKNOD = 1 << 0, @@ -136,6 +144,7 @@ typedef struct CGroupContext { CPUSet startup_cpuset_cpus; CPUSet cpuset_mems; CPUSet startup_cpuset_mems; + CPUSetPartition cpuset_partition; uint64_t io_weight; uint64_t startup_io_weight; @@ -478,6 +487,7 @@ int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name); int unit_cgroup_freezer_action(Unit *u, FreezerAction action); DECLARE_STRING_TABLE_LOOKUP(freezer_action, FreezerAction); +DECLARE_STRING_TABLE_LOOKUP(cpuset_partition, CPUSetPartition); CGroupRuntime* cgroup_runtime_new(void); CGroupRuntime* cgroup_runtime_free(CGroupRuntime *crt); diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 927c133dd9..6cecc8b9e7 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -26,6 +26,7 @@ BUS_DEFINE_PROPERTY_GET(bus_property_get_tasks_max, "t", CGroupTasksMax, cgroup_ BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_cgroup_pressure_watch, cgroup_pressure_watch, CGroupPressureWatch); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cpuset_partition, cpuset_partition, CPUSetPartition); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_managed_oom_mode, managed_oom_mode, ManagedOOMMode); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_managed_oom_preference, managed_oom_preference, ManagedOOMPreference); @@ -385,6 +386,7 @@ const sd_bus_vtable bus_cgroup_vtable[] = { SD_BUS_PROPERTY("StartupAllowedCPUs", "ay", property_get_cpuset, offsetof(CGroupContext, startup_cpuset_cpus), 0), SD_BUS_PROPERTY("AllowedMemoryNodes", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_mems), 0), SD_BUS_PROPERTY("StartupAllowedMemoryNodes", "ay", property_get_cpuset, offsetof(CGroupContext, startup_cpuset_mems), 0), + SD_BUS_PROPERTY("CPUSetPartition", "s", property_get_cpuset_partition, offsetof(CGroupContext, cpuset_partition), 0), SD_BUS_PROPERTY("IOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, io_accounting), 0), SD_BUS_PROPERTY("IOWeight", "t", NULL, offsetof(CGroupContext, io_weight), 0), SD_BUS_PROPERTY("StartupIOWeight", "t", NULL, offsetof(CGroupContext, startup_io_weight), 0), @@ -1493,6 +1495,35 @@ int bus_cgroup_set_property( return 1; + } else if (streq(name, "CPUSetPartition")) { + const char *partition_str; + CPUSetPartition p; + + r = sd_bus_message_read(message, "s", &partition_str); + if (r < 0) + return r; + + if (isempty(partition_str)) + p = _CPUSET_PARTITION_INVALID; + else { + p = cpuset_partition_from_string(partition_str); + if (p < 0) + return sd_bus_error_setf(reterr_error, SD_BUS_ERROR_INVALID_ARGS, + "Invalid CPUSetPartition value: %s", partition_str); + } + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + c->cpuset_partition = p; + unit_invalidate_cgroup(u, CGROUP_MASK_CPUSET); + + if (p == _CPUSET_PARTITION_INVALID) + unit_write_settingf(u, flags, name, "%s=", name); + else + unit_write_settingf(u, flags, name, "%s=%s", name, partition_str); + } + + return 1; + } else if (streq(name, "DeviceAllow")) { const char *path, *rwm; unsigned n = 0; diff --git a/src/core/execute-serialize.c b/src/core/execute-serialize.c index 5d0ebfa37c..5f205772fd 100644 --- a/src/core/execute-serialize.c +++ b/src/core/execute-serialize.c @@ -121,6 +121,12 @@ static int exec_cgroup_context_serialize(const CGroupContext *c, FILE *f) { if (r < 0) return r; + if (c->cpuset_partition >= 0) { + r = serialize_item(f, "exec-cgroup-context-cpuset-partition", cpuset_partition_to_string(c->cpuset_partition)); + if (r < 0) + return r; + } + if (c->io_weight != CGROUP_WEIGHT_INVALID) { r = serialize_item_format(f, "exec-cgroup-context-io-weight", "%" PRIu64, c->io_weight); if (r < 0) @@ -513,6 +519,10 @@ static int exec_cgroup_context_deserialize(CGroupContext *c, FILE *f) { r = parse_cpu_set(val, &c->startup_cpuset_mems); if (r < 0) return r; + } else if ((val = startswith(l, "exec-cgroup-context-cpuset-partition="))) { + c->cpuset_partition = cpuset_partition_from_string(val); + if (c->cpuset_partition < 0) + return -EINVAL; } else if ((val = startswith(l, "exec-cgroup-context-io-weight="))) { r = safe_atou64(val, &c->io_weight); if (r < 0) diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in index 79551adad8..b8d744c1f4 100644 --- a/src/core/load-fragment-gperf.gperf.in +++ b/src/core/load-fragment-gperf.gperf.in @@ -215,6 +215,7 @@ {{type}}.StartupAllowedCPUs, config_parse_unit_cpu_set, 0, offsetof({{type}}, cgroup_context.startup_cpuset_cpus) {{type}}.AllowedMemoryNodes, config_parse_unit_cpu_set, 0, offsetof({{type}}, cgroup_context.cpuset_mems) {{type}}.StartupAllowedMemoryNodes, config_parse_unit_cpu_set, 0, offsetof({{type}}, cgroup_context.startup_cpuset_mems) +{{type}}.CPUSetPartition, config_parse_cpuset_partition, 0, offsetof({{type}}, cgroup_context.cpuset_partition) {{type}}.CPUAccounting, config_parse_warn_compat, DISABLED_LEGACY, 0 {{type}}.CPUWeight, config_parse_cg_cpu_weight, 0, offsetof({{type}}, cgroup_context.cpu_weight) {{type}}.StartupCPUWeight, config_parse_cg_cpu_weight, 0, offsetof({{type}}, cgroup_context.startup_cpu_weight) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index d08e71f9c9..2a268d813b 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -131,6 +131,7 @@ DEFINE_CONFIG_PARSE(config_parse_socket_protocol, parse_socket_protocol); DEFINE_CONFIG_PARSE(config_parse_exec_secure_bits, secure_bits_from_string); DEFINE_CONFIG_PARSE_ENUM(config_parse_collect_mode, collect_mode, CollectMode); DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy); +DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_cpuset_partition, cpuset_partition, CPUSetPartition, _CPUSET_PARTITION_INVALID); DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode); DEFINE_CONFIG_PARSE_ENUM(config_parse_protect_proc, protect_proc, ProtectProc); DEFINE_CONFIG_PARSE_ENUM(config_parse_proc_subset, proc_subset, ProcSubset); diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index ed8060b042..fafb004028 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -170,6 +170,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_mount_node); CONFIG_PARSER_PROTOTYPE(config_parse_concurrency_max); CONFIG_PARSER_PROTOTYPE(config_parse_bind_network_interface); CONFIG_PARSER_PROTOTYPE(config_parse_exec_memory_thp); +CONFIG_PARSER_PROTOTYPE(config_parse_cpuset_partition); /* gperf prototypes */ const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length); diff --git a/src/core/varlink-cgroup.c b/src/core/varlink-cgroup.c index 3793975e8c..9953707417 100644 --- a/src/core/varlink-cgroup.c +++ b/src/core/varlink-cgroup.c @@ -258,6 +258,7 @@ int unit_cgroup_context_build_json(sd_json_variant **ret, const char *name, void JSON_BUILD_PAIR_FINITE_USEC("CPUQuotaPeriodUSec", c->cpu_quota_period_usec), JSON_BUILD_PAIR_CALLBACK_NON_NULL("AllowedCPUs", cpuset_build_json, &c->cpuset_cpus), JSON_BUILD_PAIR_CALLBACK_NON_NULL("StartupAllowedCPUs", cpuset_build_json, &c->startup_cpuset_cpus), + JSON_BUILD_PAIR_ENUM("CPUSetPartition", cpuset_partition_to_string(c->cpuset_partition)), /* Memory Accounting and Control */ SD_JSON_BUILD_PAIR_BOOLEAN("MemoryAccounting", c->memory_accounting), diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 7076322d2d..9b69ebd1a9 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2403,6 +2403,7 @@ static const BusProperty cgroup_properties[] = { { "StartupAllowedCPUs", bus_append_parse_cpu_set }, { "AllowedMemoryNodes", bus_append_parse_cpu_set }, { "StartupAllowedMemoryNodes", bus_append_parse_cpu_set }, + { "CPUSetPartition", bus_append_string }, { "DisableControllers", bus_append_strv }, { "Delegate", bus_append_parse_delegate }, { "MemoryMin", bus_append_parse_resource_limit }, diff --git a/src/shared/varlink-io.systemd.Unit.c b/src/shared/varlink-io.systemd.Unit.c index 883154b2f1..e10bf76bf9 100644 --- a/src/shared/varlink-io.systemd.Unit.c +++ b/src/shared/varlink-io.systemd.Unit.c @@ -261,6 +261,12 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_FIELD_COMMENT("The device permissions"), SD_VARLINK_DEFINE_FIELD(permissions, SD_VARLINK_STRING, 0)); +static SD_VARLINK_DEFINE_ENUM_TYPE( + CPUSetPartition, + SD_VARLINK_DEFINE_ENUM_VALUE(member), + SD_VARLINK_DEFINE_ENUM_VALUE(root), + SD_VARLINK_DEFINE_ENUM_VALUE(isolated)); + static SD_VARLINK_DEFINE_STRUCT_TYPE( CGroupContext, @@ -281,6 +287,8 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE( SD_VARLINK_DEFINE_FIELD(AllowedCPUs, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#AllowedCPUs="), SD_VARLINK_DEFINE_FIELD(StartupAllowedCPUs, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE), + SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#CPUSetPartition="), + SD_VARLINK_DEFINE_FIELD_BY_TYPE(CPUSetPartition, CPUSetPartition, SD_VARLINK_NULLABLE), /* Memory Accounting and Control * https://www.freedesktop.org/software/systemd/man/latest/systemd.resource-control.html#Memory%20Accounting%20and%20Control */ @@ -1627,6 +1635,7 @@ SD_VARLINK_DEFINE_INTERFACE( &vl_type_CGroupBPFProgram, &vl_type_CGroupController, &vl_type_CGroupDeviceAllow, + &vl_type_CPUSetPartition, SD_VARLINK_SYMBOL_COMMENT("CGroup context of a unit"), &vl_type_CGroupContext, SD_VARLINK_SYMBOL_COMMENT("CGroup runtime of a unit"), diff --git a/src/test/test-bus-unit-util.c b/src/test/test-bus-unit-util.c index a330bd8054..ae2cb19c9c 100644 --- a/src/test/test-bus-unit-util.c +++ b/src/test/test-bus-unit-util.c @@ -117,6 +117,11 @@ TEST(cgroup_properties) { "StartupAllowedMemoryNodes=0", "StartupAllowedMemoryNodes=1-3", + "CPUSetPartition=member", + "CPUSetPartition=root", + "CPUSetPartition=isolated", + "CPUSetPartition=", + "DisableControllers=cpu", "DisableControllers= " " cpu cpuacct cpuset io blkio memory devices pids bpf-firewall bpf-devices "