Compare commits

..

5 Commits

Author SHA1 Message Date
Daan De Meyer cc46b9d913 sd-bus: sd_bus_set/get_method_call_timeout docs + cleanups. 2020-03-18 20:07:45 +01:00
Susant Sahani b1d6fe7055 networkctl: Add support to display bond 2020-03-18 16:12:07 +01:00
Zbigniew Jędrzejewski-Szmek 8c357762c7
Merge pull request #14749 from msekletar/cpu-aff-numa-v3
core: add support for setting CPUAffinity= to special "numa" value
2020-03-18 13:35:58 +01:00
Michal Sekletár e2b2fb7f56 core: add support for setting CPUAffinity= to special "numa" value
systemd will automatically derive CPU affinity mask from NUMA node
mask.

Fixes #13248
2020-03-16 08:57:28 +01:00
Michal Sekletár 1808f76870 shared: split out NUMA code from cpu-set-util.c to numa-util.c 2020-03-16 08:23:18 +01:00
20 changed files with 452 additions and 139 deletions

View File

@ -340,6 +340,10 @@ manpages = [
'sd_bus_set_anonymous', 'sd_bus_set_anonymous',
'sd_bus_set_trusted'], 'sd_bus_set_trusted'],
''], ''],
['sd_bus_set_method_call_timeout',
'3',
['sd_bus_get_method_call_timeout'],
''],
['sd_bus_set_sender', '3', ['sd_bus_get_sender'], ''], ['sd_bus_set_sender', '3', ['sd_bus_get_sender'], ''],
['sd_bus_set_watch_bind', '3', ['sd_bus_get_watch_bind'], ''], ['sd_bus_set_watch_bind', '3', ['sd_bus_get_watch_bind'], ''],
['sd_bus_slot_ref', ['sd_bus_slot_ref',

View File

@ -55,6 +55,7 @@
<citerefentry><refentrytitle>sd_bus_error</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_bus_error</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_error_add_map</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_bus_error_add_map</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_get_fd</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_bus_get_fd</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_get_method_call_timeout</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_get_n_queued_read</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_bus_get_n_queued_read</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_append_array</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_bus_message_append_array</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
@ -87,6 +88,7 @@
<citerefentry><refentrytitle>sd_bus_request_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_bus_request_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_set_connected_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_bus_set_connected_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_bus_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_set_method_call_timeout</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_set_sender</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_bus_set_sender</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_set_watch_bind</refentrytitle><manvolnum>3</manvolnum></citerefentry> <citerefentry><refentrytitle>sd_bus_set_watch_bind</refentrytitle><manvolnum>3</manvolnum></citerefentry>
<citerefentry><refentrytitle>sd_bus_set_close_on_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry> <citerefentry><refentrytitle>sd_bus_set_close_on_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>

View File

@ -81,15 +81,8 @@
on the reply object returned by <function>sd_bus_call()</function> or passed to the callback of on the reply object returned by <function>sd_bus_call()</function> or passed to the callback of
<function>sd_bus_call_async()</function>.</para> <function>sd_bus_call_async()</function>.</para>
<para>If <parameter>usec</parameter> is zero, the timeout set using <para>If <parameter>usec</parameter> is zero, the default D-Bus method call timeout is used. See
<citerefentry><refentrytitle>sd_bus_set_method_call_timeout</refentrytitle><manvolnum>3</manvolnum></citerefentry> <citerefentry><refentrytitle>sd_bus_get_method_call_timeout</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
is used. If no method call timeout was set, the timeout is read from the
<varname>$SYSTEMD_BUS_TIMEOUT</varname> environment variable. If this environment variable is
unset or does not contain a valid timeout, the implementation falls back to a predefined method
call timeout of 25 seconds. Note that <varname>$SYSTEMD_BUS_TIMEOUT</varname> is read once and
cached so callers should not rely on being able to change the default method call timeout at
runtime by changing the value of <varname>$SYSTEMD_BUS_TIMEOUT</varname>. Instead, call
<function>sd_bus_set_method_call_timeout()</function> to change the default method call timeout.
</para> </para>
</refsect1> </refsect1>

View File

@ -116,8 +116,8 @@
<refsect1> <refsect1>
<title>Return Value</title> <title>Return Value</title>
<para>On success, these functions return 0 or a positive integer. On failure, they return a negative <para>On success, these functions return a non-negative integer. On failure, they return a
errno-style error code.</para> negative errno-style error code.</para>
<refsect2> <refsect2>
<title>Errors</title> <title>Errors</title>

View File

@ -0,0 +1,104 @@
<?xml version='1.0'?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1+ -->
<refentry id="sd_bus_set_method_call_timeout" xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>sd_bus_set_method_call_timeout</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
<refentrytitle>sd_bus_set_method_call_timeout</refentrytitle>
<manvolnum>3</manvolnum>
</refmeta>
<refnamediv>
<refname>sd_bus_set_method_call_timeout</refname>
<refname>sd_bus_get_method_call_timeout</refname>
<refpurpose>Set or query the default D-Bus method call timeout of a bus object</refpurpose>
</refnamediv>
<refsynopsisdiv>
<funcsynopsis>
<funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>sd_bus_set_method_call_timeout</function></funcdef>
<paramdef>sd_bus *<parameter>bus</parameter></paramdef>
<paramdef>uint64_t <parameter>usec</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_bus_get_method_call_timeout</function></funcdef>
<paramdef>sd_bus *<parameter>bus</parameter></paramdef>
<paramdef>uint64_t *<parameter>ret</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><function>sd_bus_set_method_call_timeout()</function> sets the default D-Bus method call
timeout of <parameter>bus</parameter> to <parameter>usec</parameter> microseconds.</para>
<para><function>sd_bus_get_method_call_timeout()</function> queries the default D-Bus method
call timeout of <parameter>bus</parameter>. If no method call timeout was set using
<function>sd_bus_set_method_call_timeout()</function>, the timeout is read from the
<varname>$SYSTEMD_BUS_TIMEOUT</varname> environment variable. If this environment variable is
unset or does not contain a valid timeout, the implementation falls back to a predefined method
call timeout of 25 seconds. Note that <varname>$SYSTEMD_BUS_TIMEOUT</varname> is read once and
cached so callers should not rely on being able to change the default method call timeout at
runtime by changing the value of <varname>$SYSTEMD_BUS_TIMEOUT</varname>. Instead, call
<function>sd_bus_set_method_call_timeout()</function> to change the default method call timeout.
</para>
</refsect1>
<refsect1>
<title>Return Value</title>
<para>On success, these functions return a non-negative integer. On failure, they return a
negative errno-style error code.</para>
<refsect2>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>The parameters <parameter>bus</parameter> or <parameter>ret</parameter>
are <constant>NULL</constant>.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOPKG</constant></term>
<listitem><para>Bus object <parameter>bus</parameter> could not be resolved.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect2>
</refsect1>
<xi:include href="libsystemd-pkgconfig.xml" />
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_call</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_seal</refentrytitle><manvolnum>3</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View File

@ -774,10 +774,11 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
<term><varname>CPUAffinity=</varname></term> <term><varname>CPUAffinity=</varname></term>
<listitem><para>Controls the CPU affinity of the executed processes. Takes a list of CPU indices or ranges <listitem><para>Controls the CPU affinity of the executed processes. 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 separated by either whitespace or commas. Alternatively, takes a special "numa" value in which case systemd
by a dash. This option may be specified more than once, in which case the specified CPU affinity masks are automatically derives allowed CPU range based on the value of <varname>NUMAMask=</varname> option. CPU ranges
merged. If the empty string is assigned, the mask is reset, all assignments prior to this will have no are specified by the lower and upper CPU indices separated by a dash. This option may be specified more than
effect. See once, in which case the specified CPU affinity masks are merged. If the empty string is assigned, the mask
is reset, all assignments prior to this will have no effect. See
<citerefentry><refentrytitle>sched_setaffinity</refentrytitle><manvolnum>2</manvolnum></citerefentry> for <citerefentry><refentrytitle>sched_setaffinity</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
details.</para></listitem> details.</para></listitem>
</varlistentry> </varlistentry>

View File

@ -56,6 +56,8 @@ static BUS_DEFINE_PROPERTY_GET2(property_get_ioprio_priority, "i", ExecContext,
static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_empty_string, "s", NULL); static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_empty_string, "s", NULL);
static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_level, "i", int, LOG_PRI); static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_level, "i", int, LOG_PRI);
static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_facility, "i", int, LOG_FAC); static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_facility, "i", int, LOG_FAC);
static BUS_DEFINE_PROPERTY_GET(property_get_cpu_affinity_from_numa, "b", ExecContext, exec_context_get_cpu_affinity_from_numa);
static int property_get_environment_files( static int property_get_environment_files(
sd_bus *bus, sd_bus *bus,
@ -213,6 +215,7 @@ static int property_get_cpu_affinity(
sd_bus_error *error) { sd_bus_error *error) {
ExecContext *c = userdata; ExecContext *c = userdata;
_cleanup_(cpu_set_reset) CPUSet s = {};
_cleanup_free_ uint8_t *array = NULL; _cleanup_free_ uint8_t *array = NULL;
size_t allocated; size_t allocated;
@ -220,7 +223,16 @@ static int property_get_cpu_affinity(
assert(reply); assert(reply);
assert(c); assert(c);
(void) cpu_set_to_dbus(&c->cpu_set, &array, &allocated); if (c->cpu_affinity_from_numa) {
int r;
r = numa_to_cpu_set(&c->numa_policy, &s);
if (r < 0)
return r;
}
(void) cpu_set_to_dbus(c->cpu_affinity_from_numa ? &s : &c->cpu_set, &array, &allocated);
return sd_bus_message_append_array(reply, 'y', array, allocated); return sd_bus_message_append_array(reply, 'y', array, allocated);
} }
@ -741,6 +753,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CPUAffinityFromNUMA", "b", property_get_cpu_affinity_from_numa, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NUMAPolicy", "i", property_get_numa_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("NUMAPolicy", "i", property_get_numa_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NUMAMask", "ay", property_get_numa_mask, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("NUMAMask", "ay", property_get_numa_mask, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@ -1770,6 +1783,20 @@ int bus_exec_context_set_transient_property(
return 1; return 1;
} else if (streq(name, "CPUAffinityFromNUMA")) {
int q;
r = sd_bus_message_read_basic(message, 'b', &q);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
c->cpu_affinity_from_numa = q;
unit_write_settingf(u, flags, name, "%s=%s", "CPUAffinity", "numa");
}
return 1;
} else if (streq(name, "NUMAPolicy")) { } else if (streq(name, "NUMAPolicy")) {
int32_t type; int32_t type;
@ -1784,6 +1811,7 @@ int bus_exec_context_set_transient_property(
c->numa_policy.type = type; c->numa_policy.type = type;
return 1; return 1;
} else if (streq(name, "Nice")) { } else if (streq(name, "Nice")) {
int32_t q; int32_t q;

View File

@ -3021,6 +3021,33 @@ static int exec_parameters_get_cgroup_path(const ExecParameters *params, char **
return using_subcgroup; return using_subcgroup;
} }
static int exec_context_cpu_affinity_from_numa(const ExecContext *c, CPUSet *ret) {
_cleanup_(cpu_set_reset) CPUSet s = {};
int r;
assert(c);
assert(ret);
if (!c->numa_policy.nodes.set) {
log_debug("Can't derive CPU affinity mask from NUMA mask because NUMA mask is not set, ignoring");
return 0;
}
r = numa_to_cpu_set(&c->numa_policy, &s);
if (r < 0)
return r;
cpu_set_reset(ret);
return cpu_set_add_all(ret, &s);
}
bool exec_context_get_cpu_affinity_from_numa(const ExecContext *c) {
assert(c);
return c->cpu_affinity_from_numa;
}
static int exec_child( static int exec_child(
Unit *unit, Unit *unit,
const ExecCommand *command, const ExecCommand *command,
@ -3318,11 +3345,26 @@ static int exec_child(
} }
} }
if (context->cpu_set.set) if (context->cpu_affinity_from_numa || context->cpu_set.set) {
if (sched_setaffinity(0, context->cpu_set.allocated, context->cpu_set.set) < 0) { _cleanup_(cpu_set_reset) CPUSet converted_cpu_set = {};
const CPUSet *cpu_set;
if (context->cpu_affinity_from_numa) {
r = exec_context_cpu_affinity_from_numa(context, &converted_cpu_set);
if (r < 0) {
*exit_status = EXIT_CPUAFFINITY;
return log_unit_error_errno(unit, r, "Failed to derive CPU affinity mask from NUMA mask: %m");
}
cpu_set = &converted_cpu_set;
} else
cpu_set = &context->cpu_set;
if (sched_setaffinity(0, cpu_set->allocated, cpu_set->set) < 0) {
*exit_status = EXIT_CPUAFFINITY; *exit_status = EXIT_CPUAFFINITY;
return log_unit_error_errno(unit, errno, "Failed to set up CPU affinity: %m"); return log_unit_error_errno(unit, errno, "Failed to set up CPU affinity: %m");
} }
}
if (mpol_is_valid(numa_policy_get_type(&context->numa_policy))) { if (mpol_is_valid(numa_policy_get_type(&context->numa_policy))) {
r = apply_numa_policy(&context->numa_policy); r = apply_numa_policy(&context->numa_policy);

View File

@ -21,6 +21,7 @@ typedef struct Manager Manager;
#include "missing_resource.h" #include "missing_resource.h"
#include "namespace.h" #include "namespace.h"
#include "nsflags.h" #include "nsflags.h"
#include "numa-util.h"
#include "time-util.h" #include "time-util.h"
#define EXEC_STDIN_DATA_MAX (64U*1024U*1024U) #define EXEC_STDIN_DATA_MAX (64U*1024U*1024U)
@ -181,6 +182,7 @@ struct ExecContext {
CPUSet cpu_set; CPUSet cpu_set;
NUMAPolicy numa_policy; NUMAPolicy numa_policy;
bool cpu_affinity_from_numa;
ExecInput std_input; ExecInput std_input;
ExecOutput std_output; ExecOutput std_output;
@ -405,6 +407,8 @@ void exec_runtime_vacuum(Manager *m);
void exec_params_clear(ExecParameters *p); void exec_params_clear(ExecParameters *p);
bool exec_context_get_cpu_affinity_from_numa(const ExecContext *c);
const char* exec_output_to_string(ExecOutput i) _const_; const char* exec_output_to_string(ExecOutput i) _const_;
ExecOutput exec_output_from_string(const char *s) _pure_; ExecOutput exec_output_from_string(const char *s) _pure_;

View File

@ -1330,13 +1330,25 @@ int config_parse_exec_cpu_affinity(const char *unit,
void *userdata) { void *userdata) {
ExecContext *c = data; ExecContext *c = data;
int r;
assert(filename); assert(filename);
assert(lvalue); assert(lvalue);
assert(rvalue); assert(rvalue);
assert(data); assert(data);
return parse_cpu_set_extend(rvalue, &c->cpu_set, true, unit, filename, line, lvalue); if (streq(rvalue, "numa")) {
c->cpu_affinity_from_numa = true;
cpu_set_reset(&c->cpu_set);
return 0;
}
r = parse_cpu_set_extend(rvalue, &c->cpu_set, true, unit, filename, line, lvalue);
if (r >= 0)
c->cpu_affinity_from_numa = false;
return r;
} }
int config_parse_capability_set( int config_parse_capability_set(

View File

@ -161,6 +161,12 @@ typedef struct LinkInfo {
union in_addr_union local; union in_addr_union local;
union in_addr_union remote; union in_addr_union remote;
/* bonding info */
uint8_t mode;
uint32_t miimon;
uint32_t updelay;
uint32_t downdelay;
/* ethtool info */ /* ethtool info */
int autonegotiation; int autonegotiation;
uint64_t speed; uint64_t speed;
@ -229,7 +235,11 @@ static int decode_netdev(sd_netlink_message *m, LinkInfo *info) {
(void) sd_netlink_message_read_u32(m, IFLA_BR_STP_STATE, &info->stp_state); (void) sd_netlink_message_read_u32(m, IFLA_BR_STP_STATE, &info->stp_state);
(void) sd_netlink_message_read_u16(m, IFLA_BR_PRIORITY, &info->priority); (void) sd_netlink_message_read_u16(m, IFLA_BR_PRIORITY, &info->priority);
(void) sd_netlink_message_read_u8(m, IFLA_BR_MCAST_IGMP_VERSION, &info->mcast_igmp_version); (void) sd_netlink_message_read_u8(m, IFLA_BR_MCAST_IGMP_VERSION, &info->mcast_igmp_version);
} if (streq(received_kind, "bond")) {
(void) sd_netlink_message_read_u8(m, IFLA_BOND_MODE, &info->mode);
(void) sd_netlink_message_read_u32(m, IFLA_BOND_MIIMON, &info->miimon);
(void) sd_netlink_message_read_u32(m, IFLA_BOND_DOWNDELAY, &info->downdelay);
(void) sd_netlink_message_read_u32(m, IFLA_BOND_UPDELAY, &info->updelay);
} else if (streq(received_kind, "vxlan")) { } else if (streq(received_kind, "vxlan")) {
(void) sd_netlink_message_read_u32(m, IFLA_VXLAN_ID, &info->vxlan_info.vni); (void) sd_netlink_message_read_u32(m, IFLA_VXLAN_ID, &info->vxlan_info.vni);
@ -1434,6 +1444,35 @@ static int link_status_one(
if (r < 0) if (r < 0)
return table_log_add_error(r); return table_log_add_error(r);
} else if (streq_ptr(info->netdev_kind, "bond")) {
static const struct {
const char *mode;
} mode_table[] = {
{ "balance-rr" },
{ "active-backup" },
{ "balance-xor" },
{ "broadcast" },
{ "802.3ad" },
{ "balance-tlb" },
{ "balance-alb" },
};
r = table_add_many(table,
TABLE_EMPTY,
TABLE_STRING, "Mode:",
TABLE_STRING, mode_table[info->mode],
TABLE_EMPTY,
TABLE_STRING, "Miimon:",
TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->miimon),
TABLE_EMPTY,
TABLE_STRING, "Updelay:",
TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->updelay),
TABLE_EMPTY,
TABLE_STRING, "Downdelay:",
TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->downdelay));
if (r < 0)
return table_log_add_error(r);
} else if (streq_ptr(info->netdev_kind, "vxlan")) { } else if (streq_ptr(info->netdev_kind, "vxlan")) {
if (info->vxlan_info.vni > 0) { if (info->vxlan_info.vni > 0) {
r = table_add_many(table, r = table_add_many(table,

View File

@ -21,6 +21,7 @@
#include "missing_fs.h" #include "missing_fs.h"
#include "mountpoint-util.h" #include "mountpoint-util.h"
#include "nsflags.h" #include "nsflags.h"
#include "numa-util.h"
#include "parse-util.h" #include "parse-util.h"
#include "process-util.h" #include "process-util.h"
#include "rlimit-util.h" #include "rlimit-util.h"
@ -28,6 +29,7 @@
#include "signal-util.h" #include "signal-util.h"
#include "socket-util.h" #include "socket-util.h"
#include "sort-util.h" #include "sort-util.h"
#include "stdio-util.h"
#include "string-util.h" #include "string-util.h"
#include "syslog-util.h" #include "syslog-util.h"
#include "terminal-util.h" #include "terminal-util.h"
@ -1102,6 +1104,13 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
_cleanup_free_ uint8_t *array = NULL; _cleanup_free_ uint8_t *array = NULL;
size_t allocated; size_t allocated;
if (eq && streq(eq, "numa")) {
r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
if (r < 0)
return bus_log_create_error(r);
return r;
}
r = parse_cpu_set(eq, &cpuset); r = parse_cpu_set(eq, &cpuset);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s value: %s", field, eq); return log_error_errno(r, "Failed to parse %s value: %s", field, eq);

View File

@ -14,11 +14,9 @@
#include "log.h" #include "log.h"
#include "macro.h" #include "macro.h"
#include "memory-util.h" #include "memory-util.h"
#include "missing_syscall.h"
#include "parse-util.h" #include "parse-util.h"
#include "stat-util.h" #include "stat-util.h"
#include "string-util.h" #include "string-util.h"
#include "string-table.h"
#include "strv.h" #include "strv.h"
#include "util.h" #include "util.h"
@ -133,7 +131,7 @@ int cpu_set_add_all(CPUSet *a, const CPUSet *b) {
return r; return r;
} }
return 0; return 1;
} }
int parse_cpu_set_full( int parse_cpu_set_full(
@ -218,7 +216,7 @@ int parse_cpu_set_extend(
if (!old->set) { if (!old->set) {
*old = cpuset; *old = cpuset;
cpuset = (CPUSet) {}; cpuset = (CPUSet) {};
return 0; return 1;
} }
return cpu_set_add_all(old, &cpuset); return cpu_set_add_all(old, &cpuset);
@ -295,88 +293,3 @@ int cpu_set_from_dbus(const uint8_t *bits, size_t size, CPUSet *set) {
s = (CPUSet) {}; s = (CPUSet) {};
return 0; return 0;
} }
bool numa_policy_is_valid(const NUMAPolicy *policy) {
assert(policy);
if (!mpol_is_valid(numa_policy_get_type(policy)))
return false;
if (!policy->nodes.set &&
!IN_SET(numa_policy_get_type(policy), MPOL_DEFAULT, MPOL_LOCAL, MPOL_PREFERRED))
return false;
if (policy->nodes.set &&
numa_policy_get_type(policy) == MPOL_PREFERRED &&
CPU_COUNT_S(policy->nodes.allocated, policy->nodes.set) != 1)
return false;
return true;
}
static int numa_policy_to_mempolicy(const NUMAPolicy *policy, unsigned long *ret_maxnode, unsigned long **ret_nodes) {
unsigned node, bits = 0, ulong_bits;
_cleanup_free_ unsigned long *out = NULL;
assert(policy);
assert(ret_maxnode);
assert(ret_nodes);
if (IN_SET(numa_policy_get_type(policy), MPOL_DEFAULT, MPOL_LOCAL) ||
(numa_policy_get_type(policy) == MPOL_PREFERRED && !policy->nodes.set)) {
*ret_nodes = NULL;
*ret_maxnode = 0;
return 0;
}
bits = policy->nodes.allocated * 8;
ulong_bits = sizeof(unsigned long) * 8;
out = new0(unsigned long, DIV_ROUND_UP(policy->nodes.allocated, sizeof(unsigned long)));
if (!out)
return -ENOMEM;
/* We don't make any assumptions about internal type libc is using to store NUMA node mask.
Hence we need to convert the node mask to the representation expected by set_mempolicy() */
for (node = 0; node < bits; node++)
if (CPU_ISSET_S(node, policy->nodes.allocated, policy->nodes.set))
out[node / ulong_bits] |= 1ul << (node % ulong_bits);
*ret_nodes = TAKE_PTR(out);
*ret_maxnode = bits + 1;
return 0;
}
int apply_numa_policy(const NUMAPolicy *policy) {
int r;
_cleanup_free_ unsigned long *nodes = NULL;
unsigned long maxnode;
assert(policy);
if (get_mempolicy(NULL, NULL, 0, 0, 0) < 0 && errno == ENOSYS)
return -EOPNOTSUPP;
if (!numa_policy_is_valid(policy))
return -EINVAL;
r = numa_policy_to_mempolicy(policy, &maxnode, &nodes);
if (r < 0)
return r;
r = set_mempolicy(numa_policy_get_type(policy), nodes, maxnode);
if (r < 0)
return -errno;
return 0;
}
static const char* const mpol_table[] = {
[MPOL_DEFAULT] = "default",
[MPOL_PREFERRED] = "preferred",
[MPOL_BIND] = "bind",
[MPOL_INTERLEAVE] = "interleave",
[MPOL_LOCAL] = "local",
};
DEFINE_STRING_TABLE_LOOKUP(mpol, int);

View File

@ -49,30 +49,3 @@ int cpu_set_to_dbus(const CPUSet *set, uint8_t **ret, size_t *allocated);
int cpu_set_from_dbus(const uint8_t *bits, size_t size, CPUSet *set); int cpu_set_from_dbus(const uint8_t *bits, size_t size, CPUSet *set);
int cpus_in_affinity_mask(void); int cpus_in_affinity_mask(void);
static inline bool mpol_is_valid(int t) {
return t >= MPOL_DEFAULT && t <= MPOL_LOCAL;
}
typedef struct NUMAPolicy {
/* Always use numa_policy_get_type() to read the value */
int type;
CPUSet nodes;
} NUMAPolicy;
bool numa_policy_is_valid(const NUMAPolicy *p);
static inline int numa_policy_get_type(const NUMAPolicy *p) {
return p->type < 0 ? (p->nodes.set ? MPOL_PREFERRED : -1) : p->type;
}
static inline void numa_policy_reset(NUMAPolicy *p) {
assert(p);
cpu_set_reset(&p->nodes);
p->type = -1;
}
int apply_numa_policy(const NUMAPolicy *policy);
const char* mpol_to_string(int i) _const_;
int mpol_from_string(const char *s) _pure_;

View File

@ -147,6 +147,8 @@ shared_sources = files('''
nscd-flush.h nscd-flush.h
nsflags.c nsflags.c
nsflags.h nsflags.h
numa-util.c
numa-util.h
openssl-util.h openssl-util.h
os-util.c os-util.c
os-util.h os-util.h

135
src/shared/numa-util.c Normal file
View File

@ -0,0 +1,135 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <errno.h>
#include <sched.h>
#include "alloc-util.h"
#include "cpu-set-util.h"
#include "fileio.h"
#include "macro.h"
#include "missing_syscall.h"
#include "numa-util.h"
#include "stdio-util.h"
#include "string-table.h"
bool numa_policy_is_valid(const NUMAPolicy *policy) {
assert(policy);
if (!mpol_is_valid(numa_policy_get_type(policy)))
return false;
if (!policy->nodes.set &&
!IN_SET(numa_policy_get_type(policy), MPOL_DEFAULT, MPOL_LOCAL, MPOL_PREFERRED))
return false;
if (policy->nodes.set &&
numa_policy_get_type(policy) == MPOL_PREFERRED &&
CPU_COUNT_S(policy->nodes.allocated, policy->nodes.set) != 1)
return false;
return true;
}
static int numa_policy_to_mempolicy(const NUMAPolicy *policy, unsigned long *ret_maxnode, unsigned long **ret_nodes) {
unsigned node, bits = 0, ulong_bits;
_cleanup_free_ unsigned long *out = NULL;
assert(policy);
assert(ret_maxnode);
assert(ret_nodes);
if (IN_SET(numa_policy_get_type(policy), MPOL_DEFAULT, MPOL_LOCAL) ||
(numa_policy_get_type(policy) == MPOL_PREFERRED && !policy->nodes.set)) {
*ret_nodes = NULL;
*ret_maxnode = 0;
return 0;
}
bits = policy->nodes.allocated * 8;
ulong_bits = sizeof(unsigned long) * 8;
out = new0(unsigned long, DIV_ROUND_UP(policy->nodes.allocated, sizeof(unsigned long)));
if (!out)
return -ENOMEM;
/* We don't make any assumptions about internal type libc is using to store NUMA node mask.
Hence we need to convert the node mask to the representation expected by set_mempolicy() */
for (node = 0; node < bits; node++)
if (CPU_ISSET_S(node, policy->nodes.allocated, policy->nodes.set))
out[node / ulong_bits] |= 1ul << (node % ulong_bits);
*ret_nodes = TAKE_PTR(out);
*ret_maxnode = bits + 1;
return 0;
}
int apply_numa_policy(const NUMAPolicy *policy) {
int r;
_cleanup_free_ unsigned long *nodes = NULL;
unsigned long maxnode;
assert(policy);
if (get_mempolicy(NULL, NULL, 0, 0, 0) < 0 && errno == ENOSYS)
return -EOPNOTSUPP;
if (!numa_policy_is_valid(policy))
return -EINVAL;
r = numa_policy_to_mempolicy(policy, &maxnode, &nodes);
if (r < 0)
return r;
r = set_mempolicy(numa_policy_get_type(policy), nodes, maxnode);
if (r < 0)
return -errno;
return 0;
}
int numa_to_cpu_set(const NUMAPolicy *policy, CPUSet *ret) {
int r;
size_t i;
_cleanup_(cpu_set_reset) CPUSet s = {};
assert(policy);
assert(ret);
for (i = 0; i < policy->nodes.allocated * 8; i++) {
_cleanup_free_ char *l = NULL;
char p[STRLEN("/sys/devices/system/node/node//cpulist") + DECIMAL_STR_MAX(size_t) + 1];
_cleanup_(cpu_set_reset) CPUSet part = {};
if (!CPU_ISSET_S(i, policy->nodes.allocated, policy->nodes.set))
continue;
xsprintf(p, "/sys/devices/system/node/node%zu/cpulist", i);
r = read_one_line_file(p, &l);
if (r < 0)
return r;
r = parse_cpu_set(l, &part);
if (r < 0)
return r;
r = cpu_set_add_all(&s, &part);
if (r < 0)
return r;
}
*ret = s;
s = (CPUSet) {};
return 0;
}
static const char* const mpol_table[] = {
[MPOL_DEFAULT] = "default",
[MPOL_PREFERRED] = "preferred",
[MPOL_BIND] = "bind",
[MPOL_INTERLEAVE] = "interleave",
[MPOL_LOCAL] = "local",
};
DEFINE_STRING_TABLE_LOOKUP(mpol, int);

33
src/shared/numa-util.h Normal file
View File

@ -0,0 +1,33 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include "cpu-set-util.h"
#include "missing_syscall.h"
static inline bool mpol_is_valid(int t) {
return t >= MPOL_DEFAULT && t <= MPOL_LOCAL;
}
typedef struct NUMAPolicy {
/* Always use numa_policy_get_type() to read the value */
int type;
CPUSet nodes;
} NUMAPolicy;
bool numa_policy_is_valid(const NUMAPolicy *p);
static inline int numa_policy_get_type(const NUMAPolicy *p) {
return p->type < 0 ? (p->nodes.set ? MPOL_PREFERRED : -1) : p->type;
}
static inline void numa_policy_reset(NUMAPolicy *p) {
assert(p);
cpu_set_reset(&p->nodes);
p->type = -1;
}
int apply_numa_policy(const NUMAPolicy *policy);
int numa_to_cpu_set(const NUMAPolicy *policy, CPUSet *set);
const char* mpol_to_string(int i) _const_;
int mpol_from_string(const char *s) _pure_;

View File

@ -58,6 +58,7 @@
#include "main-func.h" #include "main-func.h"
#include "memory-util.h" #include "memory-util.h"
#include "mkdir.h" #include "mkdir.h"
#include "numa-util.h"
#include "pager.h" #include "pager.h"
#include "parse-util.h" #include "parse-util.h"
#include "path-lookup.h" #include "path-lookup.h"

View File

@ -216,12 +216,12 @@ static void test_parse_cpu_set_extend(void) {
log_info("/* %s */", __func__); log_info("/* %s */", __func__);
assert_se(parse_cpu_set_extend("1 3", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); assert_se(parse_cpu_set_extend("1 3", &c, true, NULL, "fake", 1, "CPUAffinity") == 1);
assert_se(CPU_COUNT_S(c.allocated, c.set) == 2); assert_se(CPU_COUNT_S(c.allocated, c.set) == 2);
assert_se(s1 = cpu_set_to_string(&c)); assert_se(s1 = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", s1); log_info("cpu_set_to_string: %s", s1);
assert_se(parse_cpu_set_extend("4", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); assert_se(parse_cpu_set_extend("4", &c, true, NULL, "fake", 1, "CPUAffinity") == 1);
assert_se(CPU_COUNT_S(c.allocated, c.set) == 3); assert_se(CPU_COUNT_S(c.allocated, c.set) == 3);
assert_se(s2 = cpu_set_to_string(&c)); assert_se(s2 = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", s2); log_info("cpu_set_to_string: %s", s2);
@ -238,7 +238,7 @@ static void test_cpu_set_to_from_dbus(void) {
log_info("/* %s */", __func__); log_info("/* %s */", __func__);
assert_se(parse_cpu_set_extend("1 3 8 100-200", &c, true, NULL, "fake", 1, "CPUAffinity") == 0); assert_se(parse_cpu_set_extend("1 3 8 100-200", &c, true, NULL, "fake", 1, "CPUAffinity") == 1);
assert_se(s = cpu_set_to_string(&c)); assert_se(s = cpu_set_to_string(&c));
log_info("cpu_set_to_string: %s", s); log_info("cpu_set_to_string: %s", s);
assert_se(CPU_COUNT_S(c.allocated, c.set) == 104); assert_se(CPU_COUNT_S(c.allocated, c.set) == 104);

View File

@ -279,6 +279,18 @@ else
# Maks must be ignored # Maks must be ignored
grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog
echo "Unit file CPUAffinity=NUMA support"
writeTestUnitNUMAPolicy "bind" "0"
echo "CPUAffinity=numa" >> $testUnitNUMAConf
systemctl daemon-reload
systemctl start $testUnit
systemctlCheckNUMAProperties $testUnit "bind" "0"
pid=$(systemctl show --value -p MainPID $testUnit)
cpulist=$(cat /sys/devices/system/node/node0/cpulist)
affinity_systemd=$(systemctl show --value -p CPUAffinity $testUnit)
[ $cpulist = $affinity_systemd ]
pid1StopUnit $testUnit
echo "systemd-run NUMAPolicy support" echo "systemd-run NUMAPolicy support"
runUnit='numa-systemd-run-test.service' runUnit='numa-systemd-run-test.service'
@ -309,6 +321,12 @@ else
systemd-run -p NUMAPolicy=local -p NUMAMask=0 --unit $runUnit sleep 1000 systemd-run -p NUMAPolicy=local -p NUMAMask=0 --unit $runUnit sleep 1000
systemctlCheckNUMAProperties $runUnit "local" "" systemctlCheckNUMAProperties $runUnit "local" ""
pid1StopUnit $runUnit pid1StopUnit $runUnit
systemd-run -p NUMAPolicy=local -p NUMAMask=0 -p CPUAffinity=numa --unit $runUnit sleep 1000
systemctlCheckNUMAProperties $runUnit "local" ""
systemctl cat $runUnit | grep -q 'CPUAffinity=numa'
pid1StopUnit $runUnit
fi fi
# Cleanup # Cleanup