From: glemco <32201227+glemco@users.noreply.github.com> Date: Sun, 10 May 2026 09:48:27 +0000 (+0200) Subject: cgroup: Add CPUSetPartition= setting X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=43b53679da0a088dab6c8ff966a0ccbfcdeeafde;p=thirdparty%2Fsystemd.git cgroup: Add CPUSetPartition= setting Add support for configuring cpuset partition type via the CPUSetPartition= unit file setting. This controls the kernel's cpuset.cpus.partition cgroup attribute. The setting takes one of "member", "root", or "isolated". This is useful for real-time workloads that require dedicated CPU resources without interference from other processes. When set, systemd will write the partition type to the cpuset.cpus.partition cgroup file. If the kernel rejects the value (e.g., due to partition hierarchy rules), a warning is logged and the unit continues with the kernel's default partition type. Co-developed-by: Claude Sonnet 4.5 Signed-off-by: Gabriele Monaco --- diff --git a/docs/TRANSIENT-SETTINGS.md b/docs/TRANSIENT-SETTINGS.md index 652ac3d95e6..3ea51163499 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 847e76f95c7..5474dd788ed 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 b5d559849dc..fcad4b31839 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 acf2e8147f4..52d73b3747e 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 d9a6ded1102..b7213d8d594 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 927c133dd9e..6cecc8b9e74 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 5d0ebfa37c0..5f205772fd8 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 79551adad8b..b8d744c1f49 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 d08e71f9c97..2a268d813b5 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 ed8060b0428..fafb0040283 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 3793975e8cc..9953707417d 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 7076322d2d3..9b69ebd1a93 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 883154b2f19..e10bf76bf9b 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 a330bd80545..ae2cb19c9ce 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 "