diff options
29 files changed, 407 insertions, 12 deletions
diff --git a/docs/TRANSIENT-SETTINGS.md b/docs/TRANSIENT-SETTINGS.md index 7ba5837e81..08d317ca41 100644 --- a/docs/TRANSIENT-SETTINGS.md +++ b/docs/TRANSIENT-SETTINGS.md @@ -226,6 +226,8 @@ All cgroup/resource control settings are available for transient units ✓ StartupCPUShares= ✓ CPUQuota= ✓ CPUQuotaPeriodSec= +✓ AllowedCPUs= +✓ AllowedMemoryNodes= ✓ MemoryAccounting= ✓ DefaultMemoryMin= ✓ MemoryMin= diff --git a/man/machinectl.xml b/man/machinectl.xml index 357574f3f7..ebec72317f 100644 --- a/man/machinectl.xml +++ b/man/machinectl.xml @@ -695,7 +695,7 @@ server, under the same URL as the <filename>.tar</filename> file. With <option>--verify=checksum</option>, only the SHA256 checksum for the file is verified, based on the <filename>.sha256</filename> - suffixed file or the<filename>SHA256SUMS</filename> file. + suffixed file or the <filename>SHA256SUMS</filename> file. With <option>--verify=signature</option>, the sha checksum file is first verified with the inline signature in the <filename>.sha256</filename> file or the detached GPG signature file diff --git a/man/systemd.link.xml b/man/systemd.link.xml index 7ea9a71107..5013e7e9b5 100644 --- a/man/systemd.link.xml +++ b/man/systemd.link.xml @@ -624,6 +624,19 @@ <para>Sets the number of combined set channels (a number between 1 and 4294967295).</para> </listitem> </varlistentry> + <varlistentry> + <term><varname>RxBufferSize=</varname></term> + <listitem> + <para>Takes a integer. Specifies the NIC receive ring buffer size. When unset, the kernel's default will be used.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>TxBufferSize=</varname></term> + <listitem> + <para>Takes a integer. Specifies the NIC transmit ring buffer size. When unset, the kernel's default will be used.</para> + </listitem> + </varlistentry> + </variablelist> </refsect1> diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index d8fa24727a..98a0741359 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -215,6 +215,36 @@ </varlistentry> <varlistentry> + <term><varname>AllowedCPUs=</varname></term> + + <listitem> + <para>Restrict processes to be executed on specific CPUs. Takes a list of CPU indices or ranges separated by either + whitespace or commas. CPU ranges are specified by the lower and upper CPU indices separated by a dash.</para> + + <para>Setting <varname>AllowedCPUs=</varname> doesn't guarantee that all of the CPUs will be used by the processes + as it may be limited by parent units. The effective configuration is reported as <varname>EffectiveCPUs=</varname>.</para> + + <para>This setting is supported only with the unified control group hierarchy.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>AllowedMemoryNodes=</varname></term> + + <listitem> + <para>Restrict processes to be executed on specific memory NUMA nodes. Takes a list of memory NUMA nodes indices + or ranges separated by either whitespace or commas. Memory NUMA nodes ranges are specified by the lower and upper + CPU indices separated by a dash.</para> + + <para>Setting <varname>AllowedMemoryNodes=</varname> doesn't guarantee that all of the memory NUMA nodes will + be used by the processes as it may be limited by parent units. The effective configuration is reported as + <varname>EffectiveMemoryNodes=</varname>.</para> + + <para>This setting is supported only with the unified control group hierarchy.</para> + </listitem> + </varlistentry> + + <varlistentry> <term><varname>MemoryAccounting=</varname></term> <listitem> diff --git a/semaphoreci/semaphore-runner.sh b/semaphoreci/semaphore-runner.sh index 184134e6a3..9e98638dcd 100755 --- a/semaphoreci/semaphore-runner.sh +++ b/semaphoreci/semaphore-runner.sh @@ -36,6 +36,8 @@ apt-get -q --allow-releaseinfo-change update apt-get -y dist-upgrade apt-get install -y eatmydata apt-get purge --auto-remove -y unattended-upgrades +systemctl unmask systemd-networkd +systemctl enable systemd-networkd EOF sudo lxc-stop -n $CONTAINER } diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index d5c33014d7..2a359a6063 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -2435,8 +2435,7 @@ int cg_mask_supported(CGroupMask *ret) { if (r < 0) return r; - /* Currently, we support the cpu, memory, io and pids controller in the unified hierarchy, mask - * everything else off. */ + /* Mask controllers that are not supported in unified hierarchy. */ mask &= CGROUP_MASK_V2; } else { @@ -2905,6 +2904,7 @@ bool fd_is_cgroup_fs(int fd) { static const char *const cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = { [CGROUP_CONTROLLER_CPU] = "cpu", [CGROUP_CONTROLLER_CPUACCT] = "cpuacct", + [CGROUP_CONTROLLER_CPUSET] = "cpuset", [CGROUP_CONTROLLER_IO] = "io", [CGROUP_CONTROLLER_BLKIO] = "blkio", [CGROUP_CONTROLLER_MEMORY] = "memory", diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index a39ab451b9..ab094fdc4f 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -20,6 +20,7 @@ typedef enum CGroupController { /* Original cgroup controllers */ CGROUP_CONTROLLER_CPU, CGROUP_CONTROLLER_CPUACCT, /* v1 only */ + CGROUP_CONTROLLER_CPUSET, /* v2 only */ CGROUP_CONTROLLER_IO, /* v2 only */ CGROUP_CONTROLLER_BLKIO, /* v1 only */ CGROUP_CONTROLLER_MEMORY, @@ -40,6 +41,7 @@ typedef enum CGroupController { typedef enum CGroupMask { CGROUP_MASK_CPU = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPU), CGROUP_MASK_CPUACCT = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUACCT), + CGROUP_MASK_CPUSET = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUSET), CGROUP_MASK_IO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_IO), CGROUP_MASK_BLKIO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BLKIO), CGROUP_MASK_MEMORY = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_MEMORY), @@ -52,7 +54,7 @@ typedef enum CGroupMask { CGROUP_MASK_V1 = CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT|CGROUP_MASK_BLKIO|CGROUP_MASK_MEMORY|CGROUP_MASK_DEVICES|CGROUP_MASK_PIDS, /* All real cgroup v2 controllers */ - CGROUP_MASK_V2 = CGROUP_MASK_CPU|CGROUP_MASK_IO|CGROUP_MASK_MEMORY|CGROUP_MASK_PIDS, + CGROUP_MASK_V2 = CGROUP_MASK_CPU|CGROUP_MASK_CPUSET|CGROUP_MASK_IO|CGROUP_MASK_MEMORY|CGROUP_MASK_PIDS, /* All cgroup v2 BPF pseudo-controllers */ CGROUP_MASK_BPF = CGROUP_MASK_BPF_FIREWALL|CGROUP_MASK_BPF_DEVICES, diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 60a7799361..423742969e 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -202,10 +202,15 @@ void cgroup_context_done(CGroupContext *c) { c->ip_filters_ingress = strv_free(c->ip_filters_ingress); c->ip_filters_egress = strv_free(c->ip_filters_egress); + + cpu_set_reset(&c->cpuset_cpus); + cpu_set_reset(&c->cpuset_mems); } void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { _cleanup_free_ char *disable_controllers_str = NULL; + _cleanup_free_ char *cpuset_cpus = NULL; + _cleanup_free_ char *cpuset_mems = NULL; CGroupIODeviceLimit *il; CGroupIODeviceWeight *iw; CGroupIODeviceLatency *l; @@ -224,6 +229,9 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { (void) cg_mask_to_string(c->disable_controllers, &disable_controllers_str); + cpuset_cpus = cpu_set_to_range_string(&c->cpuset_cpus); + cpuset_mems = cpu_set_to_range_string(&c->cpuset_mems); + fprintf(f, "%sCPUAccounting=%s\n" "%sIOAccounting=%s\n" @@ -237,6 +245,8 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { "%sStartupCPUShares=%" PRIu64 "\n" "%sCPUQuotaPerSecSec=%s\n" "%sCPUQuotaPeriodSec=%s\n" + "%sAllowedCPUs=%s\n" + "%sAllowedMemoryNodes=%s\n" "%sIOWeight=%" PRIu64 "\n" "%sStartupIOWeight=%" PRIu64 "\n" "%sBlockIOWeight=%" PRIu64 "\n" @@ -265,6 +275,8 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { prefix, c->startup_cpu_shares, prefix, format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1), prefix, format_timespan(v, sizeof(v), c->cpu_quota_period_usec, 1), + prefix, cpuset_cpus, + prefix, cpuset_mems, prefix, c->io_weight, prefix, c->startup_io_weight, prefix, c->blockio_weight, @@ -796,6 +808,16 @@ static uint64_t cgroup_cpu_weight_to_shares(uint64_t weight) { CGROUP_CPU_SHARES_MIN, CGROUP_CPU_SHARES_MAX); } +static void cgroup_apply_unified_cpuset(Unit *u, CPUSet cpus, const char *name) { + _cleanup_free_ char *buf = NULL; + + buf = cpu_set_to_range_string(&cpus); + if (!buf) + return; + + (void) set_attribute_and_warn(u, "cpuset", name, buf); +} + static bool cgroup_context_has_io_config(CGroupContext *c) { return c->io_accounting || c->io_weight != CGROUP_WEIGHT_INVALID || @@ -1036,6 +1058,11 @@ static void cgroup_context_apply( } } + if ((apply_mask & CGROUP_MASK_CPUSET) && !is_local_root) { + cgroup_apply_unified_cpuset(u, c->cpuset_cpus, "cpuset.cpus"); + cgroup_apply_unified_cpuset(u, c->cpuset_mems, "cpuset.mems"); + } + /* The 'io' controller attributes are not exported on the host's root cgroup (being a pure cgroup v2 * controller), and in case of containers we want to leave control of these attributes to the container manager * (and we couldn't access that stuff anyway, even if we tried if proper delegation is used). */ @@ -1408,6 +1435,9 @@ static CGroupMask unit_get_cgroup_mask(Unit *u) { c->cpu_quota_per_sec_usec != USEC_INFINITY) mask |= CGROUP_MASK_CPU; + if (c->cpuset_cpus.set || c->cpuset_mems.set) + mask |= CGROUP_MASK_CPUSET; + if (cgroup_context_has_io_config(c) || cgroup_context_has_blockio_config(c)) mask |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO; @@ -3560,4 +3590,32 @@ static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = [CGROUP_STRICT] = "strict", }; +int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name) { + _cleanup_free_ char *v = NULL; + int r; + + assert(u); + assert(cpus); + + if (!u->cgroup_path) + return -ENODATA; + + if ((u->cgroup_realized_mask & CGROUP_MASK_CPUSET) == 0) + return -ENODATA; + + r = cg_all_unified(); + if (r < 0) + return r; + if (r == 0) + return -ENODATA; + if (r > 0) + r = cg_get_attribute("cpuset", u->cgroup_path, name, &v); + if (r == -ENOENT) + return -ENODATA; + if (r < 0) + return r; + + return parse_cpu_set_full(v, cpus, false, NULL, NULL, 0, NULL); +} + DEFINE_STRING_TABLE_LOOKUP(cgroup_device_policy, CGroupDevicePolicy); diff --git a/src/core/cgroup.h b/src/core/cgroup.h index d8ec070623..bca53fb980 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -4,6 +4,7 @@ #include <stdbool.h> #include "cgroup-util.h" +#include "cpu-set-util.h" #include "ip-address-access.h" #include "list.h" #include "time-util.h" @@ -92,6 +93,9 @@ struct CGroupContext { usec_t cpu_quota_per_sec_usec; usec_t cpu_quota_period_usec; + CPUSet cpuset_cpus; + CPUSet cpuset_mems; + uint64_t io_weight; uint64_t startup_io_weight; LIST_HEAD(CGroupIODeviceWeight, io_device_weights); @@ -254,3 +258,5 @@ CGroupDevicePolicy cgroup_device_policy_from_string(const char *s) _pure_; bool unit_cgroup_delegate(Unit *u); int compare_job_priority(const void *a, const void *b); + +int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name); diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 2f2313c599..bd0e73befc 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -71,6 +71,27 @@ static int property_get_delegate_controllers( return property_get_cgroup_mask(bus, path, interface, property, reply, &c->delegate_controllers, error); } +static int property_get_cpuset( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + CPUSet *cpus = userdata; + _cleanup_free_ uint8_t *array = NULL; + size_t allocated; + + assert(bus); + assert(reply); + assert(cpus); + + (void) cpu_set_to_dbus(cpus, &array, &allocated); + return sd_bus_message_append_array(reply, 'y', array, allocated); +} + static int property_get_io_device_weight( sd_bus *bus, const char *path, @@ -332,6 +353,8 @@ const sd_bus_vtable bus_cgroup_vtable[] = { SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0), SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0), SD_BUS_PROPERTY("CPUQuotaPeriodUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_period_usec), 0), + SD_BUS_PROPERTY("AllowedCPUs", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_cpus), 0), + SD_BUS_PROPERTY("AllowedMemoryNodes", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_mems), 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), @@ -856,6 +879,42 @@ int bus_cgroup_set_property( return 1; + } else if (STR_IN_SET(name, "AllowedCPUs", "AllowedMemoryNodes")) { + const void *a; + size_t n; + _cleanup_(cpu_set_reset) CPUSet new_set = {}; + + r = sd_bus_message_read_array(message, 'y', &a, &n); + if (r < 0) + return r; + + r = cpu_set_from_dbus(a, n, &new_set); + if (r < 0) + return r; + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + _cleanup_free_ char *setstr = NULL; + _cleanup_free_ char *data = NULL; + CPUSet *set; + + setstr = cpu_set_to_range_string(&new_set); + + if (streq(name, "AllowedCPUs")) + set = &c->cpuset_cpus; + else + set = &c->cpuset_mems; + + if (asprintf(&data, "%s=%s", name, setstr) < 0) + return -ENOMEM; + + cpu_set_reset(set); + cpu_set_add_all(set, &new_set); + unit_invalidate_cgroup(u, CGROUP_MASK_CPUSET); + unit_write_setting(u, flags, name, data); + } + + return 1; + } else if ((iol_type = cgroup_io_limit_type_from_string(name)) >= 0) { const char *path; unsigned n = 0; diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 9722f53162..9477c47140 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -957,6 +957,52 @@ static int property_get_cpu_usage( return sd_bus_message_append(reply, "t", ns); } +static int property_get_cpuset_cpus( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *u = userdata; + _cleanup_(cpu_set_reset) CPUSet cpus = {}; + _cleanup_free_ uint8_t *array = NULL; + size_t allocated; + + assert(bus); + assert(reply); + assert(u); + + (void) unit_get_cpuset(u, &cpus, "cpuset.cpus.effective"); + (void) cpu_set_to_dbus(&cpus, &array, &allocated); + return sd_bus_message_append_array(reply, 'y', array, allocated); +} + +static int property_get_cpuset_mems( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *u = userdata; + _cleanup_(cpu_set_reset) CPUSet mems = {}; + _cleanup_free_ uint8_t *array = NULL; + size_t allocated; + + assert(bus); + assert(reply); + assert(u); + + (void) unit_get_cpuset(u, &mems, "cpuset.mems.effective"); + (void) cpu_set_to_dbus(&mems, &array, &allocated); + return sd_bus_message_append_array(reply, 'y', array, allocated); +} + static int property_get_cgroup( sd_bus *bus, const char *path, @@ -1306,6 +1352,8 @@ const sd_bus_vtable bus_unit_cgroup_vtable[] = { SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup, 0, 0), SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0), SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0), + SD_BUS_PROPERTY("EffectiveCPUs", "ay", property_get_cpuset_cpus, 0, 0), + SD_BUS_PROPERTY("EffectiveMemoryNodes", "ay", property_get_cpuset_mems, 0, 0), SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0), SD_BUS_PROPERTY("IPIngressBytes", "t", property_get_ip_counter, 0, 0), SD_BUS_PROPERTY("IPIngressPackets", "t", property_get_ip_counter, 0, 0), diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 765d7d503d..62dff99d86 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -173,6 +173,8 @@ $1.CPUShares, config_parse_cpu_shares, 0, $1.StartupCPUShares, config_parse_cpu_shares, 0, offsetof($1, cgroup_context.startup_cpu_shares) $1.CPUQuota, config_parse_cpu_quota, 0, offsetof($1, cgroup_context) $1.CPUQuotaPeriodSec, config_parse_sec_def_infinity, 0, offsetof($1, cgroup_context.cpu_quota_period_usec) +$1.CPUSetCpus, config_parse_cpuset_cpus, 0, offsetof($1, cgroup_context) +$1.CPUSetMems, config_parse_cpuset_mems, 0, offsetof($1, cgroup_context) $1.MemoryAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.memory_accounting) $1.MemoryMin, config_parse_memory_limit, 0, offsetof($1, cgroup_context) $1.DefaultMemoryMin, config_parse_memory_limit, 0, offsetof($1, cgroup_context) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 56cad2f7b8..5fdead22f9 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3149,6 +3149,44 @@ int config_parse_cpu_quota( return 0; } +int config_parse_cpuset_cpus( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + CGroupContext *c = data; + + (void) parse_cpu_set_extend(rvalue, &c->cpuset_cpus, true, unit, filename, line, lvalue); + + return 0; +} + +int config_parse_cpuset_mems( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + CGroupContext *c = data; + + (void) parse_cpu_set_extend(rvalue, &c->cpuset_mems, true, unit, filename, line, lvalue); + + return 0; +} + int config_parse_memory_limit( const char *unit, const char *filename, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 1183987d7d..e29d58f706 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -92,6 +92,8 @@ CONFIG_PARSER_PROTOTYPE(config_parse_set_status); CONFIG_PARSER_PROTOTYPE(config_parse_namespace_path_strv); CONFIG_PARSER_PROTOTYPE(config_parse_temporary_filesystems); CONFIG_PARSER_PROTOTYPE(config_parse_cpu_quota); +CONFIG_PARSER_PROTOTYPE(config_parse_cpuset_cpus); +CONFIG_PARSER_PROTOTYPE(config_parse_cpuset_mems); CONFIG_PARSER_PROTOTYPE(config_parse_protect_home); CONFIG_PARSER_PROTOTYPE(config_parse_protect_system); CONFIG_PARSER_PROTOTYPE(config_parse_bus_name); diff --git a/src/core/unit.c b/src/core/unit.c index 9ea8c1e66c..b9fb7dbc0e 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -2789,7 +2789,7 @@ int unit_enqueue_rewatch_pids(Unit *u) { r = sd_event_source_set_priority(s, SD_EVENT_PRIORITY_IDLE); if (r < 0) - return log_error_errno(r, "Failed to adjust priority of event source for tidying watched PIDs: m"); + return log_error_errno(r, "Failed to adjust priority of event source for tidying watched PIDs: %m"); (void) sd_event_source_set_description(s, "tidy-watch-pids"); diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index 3b4c99e9ee..355b1bebf6 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -876,7 +876,7 @@ static int verify_esp_blkid( errno = 0; r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL); if (r != 0) - return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition number of \"%s\": m", node); + return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition number of \"%s\": %m", node); r = safe_atou32(v, &part); if (r < 0) return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field."); diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 612ae84fff..2cd5adfd30 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -435,6 +435,22 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons return bus_append_cg_cpu_shares_parse(m, field, eq); + if (STR_IN_SET(field, "AllowedCPUs", "AllowedMemoryNodes")) { + _cleanup_(cpu_set_reset) CPUSet cpuset = {}; + _cleanup_free_ uint8_t *array = NULL; + size_t allocated; + + r = parse_cpu_set(eq, &cpuset); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value: %s", field, eq); + + r = cpu_set_to_dbus(&cpuset, &array, &allocated); + if (r < 0) + return log_error_errno(r, "Failed to serialize CPUSet: %m"); + + return bus_append_byte_array(m, field, array, allocated); + } + if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) return bus_append_cg_blkio_weight_parse(m, field, eq); diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c index b0961df72e..4cab2ef6b0 100644 --- a/src/shared/ethtool-util.c +++ b/src/shared/ethtool-util.c @@ -365,6 +365,54 @@ int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol) { return 0; } +int ethtool_set_nic_buffer_size(int *fd, const char *ifname, netdev_ring_param *ring) { + struct ethtool_ringparam ecmd = { + .cmd = ETHTOOL_GRINGPARAM + }; + struct ifreq ifr = { + .ifr_data = (void*) &ecmd + }; + bool need_update = false; + int r; + + if (*fd < 0) { + r = ethtool_connect_or_warn(fd, true); + if (r < 0) + return r; + } + + strscpy(ifr.ifr_name, IFNAMSIZ, ifname); + + r = ioctl(*fd, SIOCETHTOOL, &ifr); + if (r < 0) + return -errno; + + if (ring->rx_pending_set) { + if (ecmd.rx_pending != ring->rx_pending) { + ecmd.rx_pending = ring->rx_pending; + need_update = true; + } + } + + if (ring->tx_pending_set) { + if (ecmd.tx_pending != ring->rx_pending) { + ecmd.tx_pending = ring->tx_pending; + need_update = true; + } + } + + if (need_update) { + ecmd.cmd = ETHTOOL_SRINGPARAM; + + r = ioctl(*fd, SIOCETHTOOL, &ifr); + if (r < 0) + return -errno; + } + + return 0; +} + + static int get_stringset(int fd, struct ifreq *ifr, int stringset_id, struct ethtool_gstrings **gstrings) { _cleanup_free_ struct ethtool_gstrings *strings = NULL; struct { @@ -858,3 +906,45 @@ int config_parse_advertise(const char *unit, return 0; } + +int config_parse_nic_buffer_size(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + netdev_ring_param *ring = data; + uint32_t k; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = safe_atou32(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse interface buffer value, ignoring: %s", rvalue); + return 0; + } + + if (k < 1) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid %s value, ignoring: %s", lvalue, rvalue); + return 0; + } + + if (streq(lvalue, "RxBufferSize")) { + ring->rx_pending = k; + ring->rx_pending_set = true; + } else if (streq(lvalue, "TxBufferSize")) { + ring->tx_pending = k; + ring->tx_pending_set = true; + } + + return 0; +} diff --git a/src/shared/ethtool-util.h b/src/shared/ethtool-util.h index 8b32b243f3..5dd7800852 100644 --- a/src/shared/ethtool-util.h +++ b/src/shared/ethtool-util.h @@ -79,12 +79,22 @@ typedef struct netdev_channels { bool combined_count_set; } netdev_channels; +typedef struct netdev_ring_param { + uint32_t rx_pending; + uint32_t tx_pending; + + bool rx_pending_set; + bool tx_pending_set; +} netdev_ring_param; + + int ethtool_get_driver(int *fd, const char *ifname, char **ret); int ethtool_get_link_info(int *fd, const char *ifname, int *ret_autonegotiation, size_t *ret_speed, Duplex *ret_duplex, NetDevPort *ret_port); int ethtool_set_speed(int *fd, const char *ifname, unsigned speed, Duplex duplex); int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol); +int ethtool_set_nic_buffer_size(int *fd, const char *ifname, netdev_ring_param *ring); int ethtool_set_features(int *fd, const char *ifname, int *features); int ethtool_set_glinksettings(int *fd, const char *ifname, int autonegotiation, uint32_t advertise[static N_ADVERTISE], @@ -108,3 +118,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_wol); CONFIG_PARSER_PROTOTYPE(config_parse_port); CONFIG_PARSER_PROTOTYPE(config_parse_channel); CONFIG_PARSER_PROTOTYPE(config_parse_advertise); +CONFIG_PARSER_PROTOTYPE(config_parse_nic_buffer_size); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 7917cbe39f..f50edbcee7 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5411,7 +5411,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m bus_print_property_value(name, expected_value, value, strempty(fields)); return 1; - } else if (contents[0] == SD_BUS_TYPE_BYTE && STR_IN_SET(name, "CPUAffinity", "NUMAMask")) { + } else if (contents[0] == SD_BUS_TYPE_BYTE && STR_IN_SET(name, "CPUAffinity", "NUMAMask", "AllowedCPUs", "AllowedMemoryNodes", "EffectiveCPUs", "EffectiveMemoryNodes")) { _cleanup_free_ char *affinity = NULL; _cleanup_(cpu_set_reset) CPUSet set = {}; const void *a; diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c index 72a6551ffd..ef3755de41 100644 --- a/src/test/test-cgroup-mask.c +++ b/src/test/test-cgroup-mask.c @@ -129,9 +129,10 @@ static void test_cg_mask_to_string_one(CGroupMask mask, const char *t) { static void test_cg_mask_to_string(void) { test_cg_mask_to_string_one(0, NULL); - test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct io blkio memory devices pids bpf-firewall bpf-devices"); + test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct cpuset io blkio memory devices pids bpf-firewall bpf-devices"); test_cg_mask_to_string_one(CGROUP_MASK_CPU, "cpu"); test_cg_mask_to_string_one(CGROUP_MASK_CPUACCT, "cpuacct"); + test_cg_mask_to_string_one(CGROUP_MASK_CPUSET, "cpuset"); test_cg_mask_to_string_one(CGROUP_MASK_IO, "io"); test_cg_mask_to_string_one(CGROUP_MASK_BLKIO, "blkio"); test_cg_mask_to_string_one(CGROUP_MASK_MEMORY, "memory"); diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c index 604c7e01be..72b6bb8eb7 100644 --- a/src/timesync/timesyncd-manager.c +++ b/src/timesync/timesyncd-manager.c @@ -617,9 +617,9 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re m->good = true; server_address_pretty(m->current_server_address, &pretty); - /* "for the first time", as further successful syncs will not be logged. */ - log_info("Synchronized to time server for the first time %s (%s).", strna(pretty), m->current_server_name->string); - sd_notifyf(false, "STATUS=Synchronized to time server for the first time %s (%s).", strna(pretty), m->current_server_name->string); + /* "Initial", as further successful syncs will not be logged. */ + log_info("Initial synchronization to time server %s (%s).", strna(pretty), m->current_server_name->string); + sd_notifyf(false, "STATUS=Initial synchronization to time server %s (%s).", strna(pretty), m->current_server_name->string); } r = manager_arm_timer(m, m->poll_interval_usec); diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf index a3d7dec88c..c6ff796efc 100644 --- a/src/udev/net/link-config-gperf.gperf +++ b/src/udev/net/link-config-gperf.gperf @@ -53,3 +53,5 @@ Link.TxChannels, config_parse_channel, 0, Link.OtherChannels, config_parse_channel, 0, offsetof(link_config, channels) Link.CombinedChannels, config_parse_channel, 0, offsetof(link_config, channels) Link.Advertise, config_parse_advertise, 0, offsetof(link_config, advertise) +Link.RxBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring) +Link.TxBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring) diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index d44af64d5e..cced62cab2 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -381,6 +381,12 @@ int link_config_apply(link_config_ctx *ctx, link_config *config, log_warning_errno(r, "Could not set channels of %s: %m", old_name); } + if (config->ring.rx_pending_set || config->ring.tx_pending_set) { + r = ethtool_set_nic_buffer_size(&ctx->ethtool_fd, old_name, &config->ring); + if (r < 0) + log_warning_errno(r, "Could not set ring buffer of %s: %m", old_name); + } + r = sd_device_get_ifindex(device, &ifindex); if (r < 0) return log_device_warning_errno(device, r, "Could not find ifindex: %m"); diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index cd99cd54d4..52a02b9b09 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -58,6 +58,7 @@ struct link_config { NetDevPort port; int features[_NET_DEV_FEAT_MAX]; netdev_channels channels; + netdev_ring_param ring; LIST_FIELDS(link_config, links); }; diff --git a/test/fuzz/fuzz-link-parser/directives.link b/test/fuzz/fuzz-link-parser/directives.link index 61155063a8..e7d0737ace 100644 --- a/test/fuzz/fuzz-link-parser/directives.link +++ b/test/fuzz/fuzz-link-parser/directives.link @@ -34,3 +34,5 @@ TxChannels= OtherChannels= CombinedChannels= Advertise= +RxBufferSize= +TxBufferSize= diff --git a/tmpfiles.d/systemd-nologin.conf b/tmpfiles.d/systemd-nologin.conf index df4dd63272..39cfd06e8b 100644 --- a/tmpfiles.d/systemd-nologin.conf +++ b/tmpfiles.d/systemd-nologin.conf @@ -5,7 +5,7 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See tmpfiles.d(5), systemd-user-session.service(5) and pam_nologin(8). +# See tmpfiles.d(5), systemd-user-sessions.service(8) and pam_nologin(8). # This file has special suffix so it is not run by mistake. F! /run/nologin 0644 - - - "System is booting up. Unprivileged users are not permitted to log in yet. Please come back later. For technical details, see pam_nologin(8)." diff --git a/units/proc-sys-fs-binfmt_misc.mount b/units/proc-sys-fs-binfmt_misc.mount index 66229ec78e..1587853e1e 100644 --- a/units/proc-sys-fs-binfmt_misc.mount +++ b/units/proc-sys-fs-binfmt_misc.mount @@ -18,3 +18,6 @@ What=binfmt_misc Where=/proc/sys/fs/binfmt_misc Type=binfmt_misc Options=nosuid,nodev,noexec + +[Install] +WantedBy=sysinit.target diff --git a/units/systemd-binfmt.service.in b/units/systemd-binfmt.service.in index e940c7c9ad..0c0f26451b 100644 --- a/units/systemd-binfmt.service.in +++ b/units/systemd-binfmt.service.in @@ -15,6 +15,7 @@ Documentation=https://www.freedesktop.org/wiki/Software/systemd/APIFileSystems DefaultDependencies=no Conflicts=shutdown.target After=proc-sys-fs-binfmt_misc.automount +After=proc-sys-fs-binfmt_misc.mount Before=sysinit.target shutdown.target ConditionPathIsReadWrite=/proc/sys/ ConditionDirectoryNotEmpty=|/lib/binfmt.d |