core: add support for disabling THPs (#39085)

Transparent Hugepages (THP) is a Linux kernel feature that manages
memory using larger pages (2MB on x86, compared to the default 4KB). The
main goal is to improve memory management efficiency and system
performance, especially for memory-intensive applications. However, it
can cause drawbacks in some scenarios, such as memory regression and
latency spikes. THP policy is governed for the entire system via
/sys/kernel/mm/transparent_hugepage/enabled.
However, it can be overridden for individual workloads via prctl(2) call.
MemoryTHP= is used to disable THPs at exec-invoke to stop providing THPs
for workloads where the drawbacks outweigh the advantages. When set to
"disable", MemoryTHP= disables THPs completely for the process,
irrespective of global THP controls.

[1] https://man7.org/linux/man-pages/man2/PR_SET_THP_DISABLE.2const.html
[2] https://man7.org/linux/man-pages/man2/madvise.2.html
[3] https://github.com/torvalds/linux/commit/9dc21bbd62edeae6f63e6f25e1edb7167452457b
This commit is contained in:
Yu Watanabe
2026-01-07 01:36:20 +09:00
committed by GitHub
21 changed files with 250 additions and 6 deletions
+32 -4
View File
@@ -3421,6 +3421,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b MemoryKSM = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s MemoryTHP = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s UserNamespacePath = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s NetworkNamespacePath = '...';
@@ -4036,6 +4038,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<!--property MemoryKSM is not documented!-->
<!--property MemoryTHP is not documented!-->
<!--property UserNamespacePath is not documented!-->
<!--property NetworkNamespacePath is not documented!-->
@@ -4784,6 +4788,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<variablelist class="dbus-property" generated="True" extra-ref="MemoryKSM"/>
<variablelist class="dbus-property" generated="True" extra-ref="MemoryTHP"/>
<variablelist class="dbus-property" generated="True" extra-ref="UserNamespacePath"/>
<variablelist class="dbus-property" generated="True" extra-ref="NetworkNamespacePath"/>
@@ -5684,6 +5690,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b MemoryKSM = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s MemoryTHP = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s UserNamespacePath = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s NetworkNamespacePath = '...';
@@ -6317,6 +6325,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
<!--property MemoryKSM is not documented!-->
<!--property MemoryTHP is not documented!-->
<!--property UserNamespacePath is not documented!-->
<!--property NetworkNamespacePath is not documented!-->
@@ -7041,6 +7051,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
<variablelist class="dbus-property" generated="True" extra-ref="MemoryKSM"/>
<variablelist class="dbus-property" generated="True" extra-ref="MemoryTHP"/>
<variablelist class="dbus-property" generated="True" extra-ref="UserNamespacePath"/>
<variablelist class="dbus-property" generated="True" extra-ref="NetworkNamespacePath"/>
@@ -7765,6 +7777,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b MemoryKSM = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s MemoryTHP = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s UserNamespacePath = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s NetworkNamespacePath = '...';
@@ -8322,6 +8336,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
<!--property MemoryKSM is not documented!-->
<!--property MemoryTHP is not documented!-->
<!--property UserNamespacePath is not documented!-->
<!--property NetworkNamespacePath is not documented!-->
@@ -8954,6 +8970,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
<variablelist class="dbus-property" generated="True" extra-ref="MemoryKSM"/>
<variablelist class="dbus-property" generated="True" extra-ref="MemoryTHP"/>
<variablelist class="dbus-property" generated="True" extra-ref="UserNamespacePath"/>
<variablelist class="dbus-property" generated="True" extra-ref="NetworkNamespacePath"/>
@@ -9811,6 +9829,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b MemoryKSM = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s MemoryTHP = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s UserNamespacePath = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s NetworkNamespacePath = '...';
@@ -10350,6 +10370,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
<!--property MemoryKSM is not documented!-->
<!--property MemoryTHP is not documented!-->
<!--property UserNamespacePath is not documented!-->
<!--property NetworkNamespacePath is not documented!-->
@@ -10964,6 +10986,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
<variablelist class="dbus-property" generated="True" extra-ref="MemoryKSM"/>
<variablelist class="dbus-property" generated="True" extra-ref="MemoryTHP"/>
<variablelist class="dbus-property" generated="True" extra-ref="UserNamespacePath"/>
<variablelist class="dbus-property" generated="True" extra-ref="NetworkNamespacePath"/>
@@ -12598,7 +12622,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
<varname>ManagedOOMKills</varname>,
<varname>ExecReloadPost</varname>, and
<varname>ExecReloadPostEx</varname> were added in version 259.</para>
<para><varname>BindNetworkInterface</varname> was added in version 260.</para>
<para><varname>BindNetworkInterface</varname>, and
<varname>MemoryTHP</varname> were added in version 260.</para>
</refsect2>
<refsect2>
<title>Socket Unit Objects</title>
@@ -12667,7 +12692,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
<para><varname>UserNamespacePath</varname>,
<varname>OOMKills</varname>, and
<varname>ManagedOOMKills</varname> were added in 259.</para>
<para><varname>BindNetworkInterface</varname> was added in version 260.</para>
<para><varname>BindNetworkInterface</varname>, and
<varname>MemoryTHP</varname> were added in version 260.</para>
</refsect2>
<refsect2>
<title>Mount Unit Objects</title>
@@ -12731,7 +12757,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
<para><varname>UserNamespacePath</varname>,
<varname>OOMKills</varname>, and
<varname>ManagedOOMKills</varname> were added in 259.</para>
<para><varname>BindNetworkInterface</varname> was added in version 260.</para>
<para><varname>BindNetworkInterface</varname>, and
<varname>MemoryTHP</varname> were added in version 260.</para>
</refsect2>
<refsect2>
<title>Swap Unit Objects</title>
@@ -12793,7 +12820,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
<para><varname>UserNamespacePath</varname>,
<varname>OOMKills</varname>, and
<varname>ManagedOOMKills</varname> were added in 259.</para>
<para><varname>BindNetworkInterface</varname> was added in version 260.</para>
<para><varname>BindNetworkInterface</varname>, and
<varname>MemoryTHP</varname> were added in version 260.</para>
</refsect2>
<refsect2>
<title>Slice Unit Objects</title>
+35
View File
@@ -2134,6 +2134,41 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>MemoryTHP=</varname></term>
<listitem><para>Transparent Hugepages (THPs) is a Linux kernel feature that manages memory
using larger pages (2MB on x86, compared to the default 4KB). The main goal is to improve memory management
efficiency and system performance, especially for memory-intensive applications.
However, it can cause drawbacks in some scenarios, such as memory regression and latency spikes.
THP policy is governed for the entire system via <filename>/sys/kernel/mm/transparent_hugepage/enabled</filename>.
However, it can be overridden for individual workloads via
<citerefentry><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
<varname>MemoryTHP=</varname> may be used to disable THPs at process invocation time to stop providing
THPs for workloads where the drawbacks outweigh the advantages.
When <varname>MemoryTHP=</varname> is set to <literal>inherit</literal> or not set at all, systemd
inherits THP settings from the process that starts it and no
<citerefentry><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>
<constant>PR_SET_THP_DISABLE</constant> call is made.
When set to <literal>disable</literal>, <varname>MemoryTHP=</varname> disables THPs completely for the process,
irrespecitive of global THP controls.
When set to <literal>madvise</literal>, <varname>MemoryTHP=</varname> disables THPs for the process except when
specifically requested via <citerefentry><refentrytitle>madvise</refentrytitle><manvolnum>2</manvolnum></citerefentry>
by the process with <constant>MADV_HUGEPAGE</constant> or <constant>MADV_COLLAPSE</constant>.
When set to <literal>system</literal>, <varname>MemoryTHP=</varname> resets the THP policy to system wide policy.
This can be used when the process that starts systemd has already disabled THPs via
<constant>PR_SET_THP_DISABLE</constant>, and we want to restore the system default THP setting at
process invokation time. For details, see
<ulink url="https://docs.kernel.org/admin-guide/mm/transhuge.html">Transparent Hugepage Support</ulink>
in the kernel documentation.</para>
<para>Note that this functionality might not be available, for example if THP is disabled in the
kernel, or the kernel does not support controlling THP at the process level through
<citerefentry><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>.</para>
<xi:include href="version-info.xml" xpointer="v260"/>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>PrivatePIDs=</varname></term>
+6
View File
@@ -58,6 +58,7 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_private_bpf, private_bpf, Priva
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_protect_home, protect_home, ProtectHome);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_protect_system, protect_system, ProtectSystem);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_personality, personality, unsigned long);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_memory_thp, memory_thp, MemoryTHP);
static BUS_DEFINE_PROPERTY_GET(property_get_ioprio, "i", ExecContext, exec_context_get_effective_ioprio);
static BUS_DEFINE_PROPERTY_GET(property_get_mount_apivfs, "b", ExecContext, exec_context_get_effective_mount_apivfs);
static BUS_DEFINE_PROPERTY_GET(property_get_bind_log_sockets, "b", ExecContext, exec_context_get_effective_bind_log_sockets);
@@ -1407,6 +1408,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("BPFDelegatePrograms", "s", property_get_bpf_delegate_programs, offsetof(ExecContext, bpf_delegate_programs), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("BPFDelegateAttachments", "s", property_get_bpf_delegate_attachments, offsetof(ExecContext, bpf_delegate_attachments), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MemoryKSM", "b", bus_property_get_tristate, offsetof(ExecContext, memory_ksm), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MemoryTHP", "s", property_get_memory_thp, offsetof(ExecContext, memory_thp), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("UserNamespacePath", "s", NULL, offsetof(ExecContext, user_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NetworkNamespacePath", "s", NULL, offsetof(ExecContext, network_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IPCNamespacePath", "s", NULL, offsetof(ExecContext, ipc_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1845,6 +1847,7 @@ static BUS_DEFINE_SET_TRANSIENT_PARSE(keyring_mode, ExecKeyringMode, exec_keyrin
static BUS_DEFINE_SET_TRANSIENT_PARSE(protect_proc, ProtectProc, protect_proc_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(proc_subset, ProcSubset, proc_subset_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(private_bpf, PrivateBPF, private_bpf_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(memory_thp, MemoryTHP, memory_thp_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE_PTR(bpf_delegate_commands, uint64_t, bpf_delegate_commands_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE_PTR(bpf_delegate_maps, uint64_t, bpf_delegate_maps_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE_PTR(bpf_delegate_programs, uint64_t, bpf_delegate_programs_from_string);
@@ -2333,6 +2336,9 @@ int bus_exec_context_set_transient_property(
if (streq(name, "MemoryKSM"))
return bus_set_transient_tristate(u, name, &c->memory_ksm, message, flags, reterr_error);
if (streq(name, "MemoryTHP"))
return bus_set_transient_memory_thp(u, name, &c->memory_thp, message, flags, reterr_error);
if (streq(name, "UtmpIdentifier"))
return bus_set_transient_string(u, name, &c->utmp_id, message, flags, reterr_error);
+36
View File
@@ -4866,6 +4866,32 @@ static int exec_fd_mark_hot(
return 1;
}
static int set_memory_thp(MemoryTHP thp) {
switch (thp) {
case MEMORY_THP_INHERIT:
return 0;
case MEMORY_THP_DISABLE:
if (prctl(PR_SET_THP_DISABLE, 1, 0, 0, 0) < 0)
return errno == EINVAL ? -EOPNOTSUPP : -errno;
return 0;
case MEMORY_THP_MADVISE:
if (prctl(PR_SET_THP_DISABLE, 1, PR_THP_DISABLE_EXCEPT_ADVISED, 0, 0) < 0)
return errno == EINVAL ? -EOPNOTSUPP : -errno;
return 0;
case MEMORY_THP_SYSTEM:
if (prctl(PR_SET_THP_DISABLE, 0, 0, 0, 0) < 0)
return errno == EINVAL ? -EOPNOTSUPP : -errno;
return 0;
default:
assert_not_reached();
}
}
static int send_handoff_timestamp(
const ExecContext *c,
ExecParameters *p,
@@ -5550,6 +5576,16 @@ int exec_invoke(
}
}
r = set_memory_thp(context->memory_thp);
if (r == -EOPNOTSUPP)
log_debug_errno(r, "Setting MemoryTHP=%s is not supported, ignoring: %m",
memory_thp_to_string(context->memory_thp));
else if (r < 0) {
*exit_status = EXIT_MEMORY_THP;
return log_error_errno(r, "Failed to set MemoryTHP=%s: %m",
memory_thp_to_string(context->memory_thp));
}
#if ENABLE_UTMP
if (context->utmp_id) {
_cleanup_free_ char *username_alloc = NULL;
+8
View File
@@ -1664,6 +1664,10 @@ static int exec_context_serialize(const ExecContext *c, FILE *f) {
if (r < 0)
return r;
r = serialize_item(f, "exec-context-memory-thp", memory_thp_to_string(c->memory_thp));
if (r < 0)
return r;
r = serialize_item(f, "exec-context-private-tmp", private_tmp_to_string(c->private_tmp));
if (r < 0)
return r;
@@ -2649,6 +2653,10 @@ static int exec_context_deserialize(ExecContext *c, FILE *f) {
r = safe_atoi(val, &c->memory_ksm);
if (r < 0)
return r;
} else if ((val = startswith(l, "exec-context-memory-thp="))) {
c->memory_thp = memory_thp_from_string(val);
if (c->memory_thp < 0)
return c->memory_thp;
} else if ((val = startswith(l, "exec-context-private-tmp="))) {
c->private_tmp = private_tmp_from_string(val);
if (c->private_tmp < 0)
+4 -2
View File
@@ -1117,7 +1117,8 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
"%sProtectHostname: %s%s%s\n"
"%sProtectProc: %s\n"
"%sProcSubset: %s\n"
"%sPrivateBPF: %s\n",
"%sPrivateBPF: %s\n"
"%sMemoryTHP: %s\n",
prefix, c->umask,
prefix, empty_to_root(c->working_directory),
prefix, empty_to_root(c->root_directory),
@@ -1145,7 +1146,8 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
prefix, protect_hostname_to_string(c->protect_hostname), c->private_hostname ? ":" : "", strempty(c->private_hostname),
prefix, protect_proc_to_string(c->protect_proc),
prefix, proc_subset_to_string(c->proc_subset),
prefix, private_bpf_to_string(c->private_bpf));
prefix, private_bpf_to_string(c->private_bpf),
prefix, memory_thp_to_string(c->memory_thp));
if (c->private_bpf == PRIVATE_BPF_YES) {
_cleanup_free_ char
+1
View File
@@ -311,6 +311,7 @@ typedef struct ExecContext {
int mount_apivfs;
int bind_log_sockets;
int memory_ksm;
MemoryTHP memory_thp;
PrivateTmp private_tmp;
PrivateTmp private_var_tmp; /* This is not an independent parameter, but calculated from other
* parameters in unit_patch_contexts(). */
+1
View File
@@ -195,6 +195,7 @@
{% endif %}
{{type}}.ProtectHostname, config_parse_protect_hostname, 0, offsetof({{type}}, exec_context)
{{type}}.MemoryKSM, config_parse_tristate, 0, offsetof({{type}}, exec_context.memory_ksm)
{{type}}.MemoryTHP, config_parse_memory_thp, 0, offsetof({{type}}, exec_context.memory_thp)
{%- endmacro -%}
{%- macro KILL_CONTEXT_CONFIG_ITEMS(type) -%}
+1
View File
@@ -163,6 +163,7 @@ DEFINE_CONFIG_PARSE_PTR(config_parse_bpf_delegate_commands, bpf_delegate_command
DEFINE_CONFIG_PARSE_PTR(config_parse_bpf_delegate_maps, bpf_delegate_maps_from_string, uint64_t);
DEFINE_CONFIG_PARSE_PTR(config_parse_bpf_delegate_programs, bpf_delegate_programs_from_string, uint64_t);
DEFINE_CONFIG_PARSE_PTR(config_parse_bpf_delegate_attachments, bpf_delegate_attachments_from_string, uint64_t);
DEFINE_CONFIG_PARSE_ENUM(config_parse_memory_thp, memory_thp, MemoryTHP);
bool contains_instance_specifier_superset(const char *s) {
const char *p, *q;
+1
View File
@@ -168,6 +168,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_cgroup_nft_set);
CONFIG_PARSER_PROTOTYPE(config_parse_mount_node);
CONFIG_PARSER_PROTOTYPE(config_parse_concurrency_max);
CONFIG_PARSER_PROTOTYPE(config_parse_bind_network_interface);
CONFIG_PARSER_PROTOTYPE(config_parse_memory_thp);
/* gperf prototypes */
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
+9
View File
@@ -4047,6 +4047,15 @@ DEFINE_STRING_TABLE_LOOKUP(bpf_delegate_map_type, uint64_t);
DEFINE_STRING_TABLE_LOOKUP(bpf_delegate_prog_type, uint64_t);
DEFINE_STRING_TABLE_LOOKUP(bpf_delegate_attach_type, uint64_t);
static const char* const memory_thp_table[_MEMORY_THP_MAX] = {
[MEMORY_THP_INHERIT] = "inherit",
[MEMORY_THP_DISABLE] = "disable",
[MEMORY_THP_MADVISE] = "madvise",
[MEMORY_THP_SYSTEM] = "system",
};
DEFINE_STRING_TABLE_LOOKUP(memory_thp, MemoryTHP);
char* bpf_delegate_to_string(uint64_t u, const char * (*parser)(uint64_t) _const_ ) {
assert(parser);
+20
View File
@@ -91,6 +91,24 @@ typedef enum PrivatePIDs {
_PRIVATE_PIDS_INVALID = -EINVAL,
} PrivatePIDs;
typedef enum MemoryTHP {
/*
* Inherit default from process that starts systemd, i.e. do not make
* any PR_SET_THP_DISABLE call.
*/
MEMORY_THP_INHERIT,
MEMORY_THP_DISABLE, /* Disable THPs completely for the prcess */
MEMORY_THP_MADVISE, /* Disable THPs for the process except when madvised */
/*
* Use system default THP setting. this can be used when the process that
* starts systemd has already disabled THPs via PR_SET_THP_DISABLE, and we
* want to restore the system default THP setting at process invokation time.
*/
MEMORY_THP_SYSTEM,
_MEMORY_THP_MAX,
_MEMORY_THP_INVALID = -EINVAL,
} MemoryTHP;
typedef struct BindMount {
char *source;
char *destination;
@@ -233,6 +251,8 @@ DECLARE_STRING_TABLE_LOOKUP(proc_subset, ProcSubset);
DECLARE_STRING_TABLE_LOOKUP(private_bpf, PrivateBPF);
DECLARE_STRING_TABLE_LOOKUP(memory_thp, MemoryTHP);
DECLARE_STRING_TABLE_LOOKUP(bpf_delegate_cmd, uint64_t);
DECLARE_STRING_TABLE_LOOKUP(bpf_delegate_map_type, uint64_t);
+1
View File
@@ -908,6 +908,7 @@ int unit_exec_context_build_json(sd_json_variant **ret, const char *name, void *
SD_JSON_BUILD_PAIR_BOOLEAN("RemoveIPC", c->remove_ipc),
JSON_BUILD_PAIR_TRISTATE_NON_NULL("PrivateMounts", c->private_mounts),
JSON_BUILD_PAIR_STRING_NON_EMPTY("MountFlags", mount_propagation_flag_to_string(c->mount_propagation_flag)),
SD_JSON_BUILD_PAIR_STRING("MemoryTHP", memory_thp_to_string(c->memory_thp)),
/* System Call Filtering */
JSON_BUILD_PAIR_CALLBACK_NON_NULL("SystemCallFilter", syscall_filter_build_json, c),
+4
View File
@@ -17,3 +17,7 @@
#ifndef PR_SET_MEMORY_MERGE
#define PR_SET_MEMORY_MERGE 67
#endif
#ifndef PR_THP_DISABLE_EXCEPT_ADVISED
#define PR_THP_DISABLE_EXCEPT_ADVISED (1 << 1)
#endif
+1
View File
@@ -2494,6 +2494,7 @@ static const BusProperty execute_properties[] = {
{ "LogRateLimitBurst", bus_append_safe_atou },
{ "TTYRows", bus_append_safe_atou },
{ "TTYColumns", bus_append_safe_atou },
{ "MemoryTHP", bus_append_string },
{ "MountFlags", bus_append_mount_propagation_flag_from_string },
{ "Environment", bus_append_strv_cunescape },
{ "UnsetEnvironment", bus_append_strv_cunescape },
+1
View File
@@ -71,6 +71,7 @@ const ExitStatusMapping exit_status_mappings[256] = {
[EXIT_CREDENTIALS] = { "CREDENTIALS", EXIT_STATUS_SYSTEMD },
[EXIT_BPF] = { "BPF", EXIT_STATUS_SYSTEMD },
[EXIT_KSM] = { "KSM", EXIT_STATUS_SYSTEMD },
[EXIT_MEMORY_THP] = { "MEMORY_THP", EXIT_STATUS_SYSTEMD },
[EXIT_EXCEPTION] = { "EXCEPTION", EXIT_STATUS_SYSTEMD },
+1
View File
@@ -70,6 +70,7 @@ enum {
EXIT_CREDENTIALS,
EXIT_BPF,
EXIT_KSM,
EXIT_MEMORY_THP,
EXIT_EXCEPTION = 255, /* Whenever we want to propagate an abnormal/signal exit, in line with bash */
};
+2
View File
@@ -626,6 +626,8 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_DEFINE_FIELD(PrivateMounts, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man"PROJECT_VERSION_STR"systemd.exec.html#MountFlags="),
SD_VARLINK_DEFINE_FIELD(MountFlags, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man"PROJECT_VERSION_STR"systemd.exec.html#MemoryTHP="),
SD_VARLINK_DEFINE_FIELD(MemoryTHP, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
/* System Call Filtering
* https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#System%20Call%20Filtering */
+5
View File
@@ -528,6 +528,11 @@ executables += [
'conditions' : ['BPF_FRAMEWORK'],
'type' : 'manual',
},
core_test_template + {
'sources' : files('test-thp.c'),
'dependencies' : common_test_dependencies,
'type' : 'manual',
},
core_test_template + {
'sources' : files('test-cgroup-cpu.c'),
},
+56
View File
@@ -0,0 +1,56 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <sys/prctl.h>
#include "tests.h"
#define PR_THP_DISABLE_NOT_SET 0
#define PR_THP_DISABLE 1
static const char *arg_mode = NULL;
static int intro(void) {
int r;
r = prctl(PR_GET_THP_DISABLE, 0, 0, 0, 0);
if (streq_ptr(arg_mode, "no-disable")) {
/* Test case: THPs should not be disabled */
if (r != PR_THP_DISABLE_NOT_SET) {
log_error("THPs disabled for the process r = %d: %m", r);
return EXIT_FAILURE;
}
} else if (streq_ptr(arg_mode, "disable")) {
/* Test case: THPs should be completely disabled */
if (r == PR_THP_DISABLE_NOT_SET)
return log_tests_skipped("Disabling THPs completely for the process not supported");
if (r != PR_THP_DISABLE) {
log_error("THPs not completely disabled for the process r = %d: %m", r);
return EXIT_FAILURE;
}
} else if (streq_ptr(arg_mode, "madvise")) {
/* Test case: THPs should be only enabled on a madvise basis */
if (r == PR_THP_DISABLE_NOT_SET)
return log_tests_skipped("Disabling THPs except for madvise not supported");
if (r != (PR_THP_DISABLE | PR_THP_DISABLE_EXCEPT_ADVISED)) {
log_error("THPs (except madvise) not completely disabled for the process r = %d: %m", r);
return EXIT_FAILURE;
}
} else {
log_error("Invalid mode: %s (expected: no-disable, disable, or madvise)", strna(arg_mode));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
log_error("Invalid number of args passed to the test %d", argc);
return EXIT_FAILURE;
}
arg_mode = argv[1];
test_setup_logging(LOG_DEBUG);
return intro();
}
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail
systemd-run --wait \
/usr/lib/systemd/tests/unit-tests/manual/test-thp no-disable
systemd-run --wait \
-p MemoryTHP=disable \
/usr/lib/systemd/tests/unit-tests/manual/test-thp disable
# The following test will always return 77 if at compile time the kernel version
# is less than 6.18. If it happens don't let the whole test fail
set +e
systemd-run --wait \
-p MemoryTHP=madvise \
/usr/lib/systemd/tests/unit-tests/manual/test-thp madvise
if [ $? -eq 77 ]; then
exit 0
fi
set -e