summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/TRANSIENT-SETTINGS.md2
-rw-r--r--man/machinectl.xml2
-rw-r--r--man/systemd.link.xml13
-rw-r--r--man/systemd.resource-control.xml30
-rwxr-xr-xsemaphoreci/semaphore-runner.sh2
-rw-r--r--src/basic/cgroup-util.c4
-rw-r--r--src/basic/cgroup-util.h4
-rw-r--r--src/core/cgroup.c58
-rw-r--r--src/core/cgroup.h6
-rw-r--r--src/core/dbus-cgroup.c59
-rw-r--r--src/core/dbus-unit.c48
-rw-r--r--src/core/load-fragment-gperf.gperf.m42
-rw-r--r--src/core/load-fragment.c38
-rw-r--r--src/core/load-fragment.h2
-rw-r--r--src/core/unit.c2
-rw-r--r--src/shared/bootspec.c2
-rw-r--r--src/shared/bus-unit-util.c16
-rw-r--r--src/shared/ethtool-util.c90
-rw-r--r--src/shared/ethtool-util.h11
-rw-r--r--src/systemctl/systemctl.c2
-rw-r--r--src/test/test-cgroup-mask.c3
-rw-r--r--src/timesync/timesyncd-manager.c6
-rw-r--r--src/udev/net/link-config-gperf.gperf2
-rw-r--r--src/udev/net/link-config.c6
-rw-r--r--src/udev/net/link-config.h1
-rw-r--r--test/fuzz/fuzz-link-parser/directives.link2
-rw-r--r--tmpfiles.d/systemd-nologin.conf2
-rw-r--r--units/proc-sys-fs-binfmt_misc.mount3
-rw-r--r--units/systemd-binfmt.service.in1
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