Compare commits

...

8 Commits

Author SHA1 Message Date
slee649 ebe90d42d3
Merge 84b25bf0b4 into bbec1c87d3 2024-11-26 10:43:36 -08:00
gerblesh bbec1c87d3 sysext: set SELinux context for hierarchies and workdir 2024-11-26 17:47:32 +00:00
Yu Watanabe f29a07f3fc man: several more assorted fixes
Continuation of 4ebbb5bfe8.
Closes #35307.
2024-11-26 17:28:14 +01:00
Luca Boccassi 0566bd9643
machine: increase timeouts in attempt to fix #35115 (#35117)
An attempt to fix https://github.com/systemd/systemd/issues/35115
2024-11-26 16:12:56 +00:00
Lennart Poettering 7b4b3a8f7b sd-varlink: fix bug when enqueuing messages with fds asynchronously
When determining the poll events to wait for we need to take the queue
of pending messages that carry fds into account. Otherwise we might end
up not waking up if such an fd-carrying message is enqueued
asynchronously (i.e. not from a dispatch callback).
2024-11-26 16:06:53 +00:00
Sea-Eun Lee 84b25bf0b4 oomd: support reloading configuration at runtime 2024-11-26 05:28:55 +00:00
Ivan Kruglov 3aa3f130c1 machine: add debug for systemd-nspawn@.service 2024-11-19 19:12:32 +01:00
Ivan Kruglov df18408ac6 machine: increase timeouts in attempt to fix #35115 2024-11-19 18:04:27 +01:00
20 changed files with 323 additions and 120 deletions

View File

@ -128,7 +128,8 @@
<para>If <option>-keep-download=yes</option> is specified the image will be downloaded and stored in <para>If <option>-keep-download=yes</option> is specified the image will be downloaded and stored in
a read-only subvolume/directory in the image directory that is named after the specified URL and its a read-only subvolume/directory in the image directory that is named after the specified URL and its
HTTP etag. A writable snapshot is then taken from this subvolume, and named after the specified local HTTP etag (see <ulink url="https://en.wikipedia.org/wiki/HTTP_ETag">HTTP ETag</ulink> for more
information). A writable snapshot is then taken from this subvolume, and named after the specified local
name. This behavior ensures that creating multiple instances of the same URL is efficient, as name. This behavior ensures that creating multiple instances of the same URL is efficient, as
multiple downloads are not necessary. In order to create only the read-only image, and avoid creating multiple downloads are not necessary. In order to create only the read-only image, and avoid creating
its writable snapshot, specify <literal>-</literal> as local name.</para> its writable snapshot, specify <literal>-</literal> as local name.</para>

View File

@ -28,7 +28,9 @@
<title>Description</title> <title>Description</title>
<para><command>pam_systemd_loadkey</command> reads a NUL-separated password list from the kernel keyring, <para><command>pam_systemd_loadkey</command> reads a NUL-separated password list from the kernel keyring,
and sets the last password in the list as the PAM authtok.</para> and sets the last password in the list as the PAM authtok, which can be used by e.g.
<citerefentry project='man-pages'><refentrytitle>pam_get_authtok</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</para>
<para>The password list is supposed to be stored in the "user" keyring of the root user, <para>The password list is supposed to be stored in the "user" keyring of the root user,
by an earlier call to by an earlier call to

View File

@ -61,7 +61,10 @@
<literal>systemd-run0</literal> PAM stack.</para> <literal>systemd-run0</literal> PAM stack.</para>
<para>Note that <command>run0</command> is implemented as an alternative multi-call invocation of <para>Note that <command>run0</command> is implemented as an alternative multi-call invocation of
<citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para> <citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry>. That is,
<command>run0</command> is a symbolic link to <command>systemd-run</command> executable file, and it
behaves as <command>run0</command> if it is invoked through the symbolic link, otherwise behaves as
<command>systemd-run</command>.</para>
</refsect1> </refsect1>
<refsect1> <refsect1>

View File

@ -127,6 +127,24 @@
</variablelist> </variablelist>
</refsect1> </refsect1>
<refsect1>
<title>Signals</title>
<variablelist>
<varlistentry>
<term><constant>SIGHUP</constant></term>
<listitem><para>Upon reception of the <constant>SIGHUP</constant> process signal
<command>systemd-oomd</command> will reload its configuration file.</para>
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
</refsect1>
<refsect1> <refsect1>
<title>See Also</title> <title>See Also</title>
<para><simplelist type="inline"> <para><simplelist type="inline">

View File

@ -41,8 +41,10 @@
<refsect1> <refsect1>
<title>Kernel Command Line</title> <title>Kernel Command Line</title>
<para><filename>systemd-rfkill</filename> understands the <para>
following kernel command line parameter:</para> <command>systemd-rfkill</command> understands the following kernel command line parameter. See also
<citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
</para>
<variablelist class='kernel-commandline-options'> <variablelist class='kernel-commandline-options'>
<varlistentry> <varlistentry>

View File

@ -394,9 +394,9 @@
<listitem><para>SBAT metadata associated with the UKI or addon. SBAT policies are useful to revoke <listitem><para>SBAT metadata associated with the UKI or addon. SBAT policies are useful to revoke
whole groups of UKIs or addons with a single, static policy update that does not take space in whole groups of UKIs or addons with a single, static policy update that does not take space in
DBX/MOKX. If not specified manually, a default metadata entry consisting of DBX/MOKX. If not specified manually, a default metadata entry consisting of
<literal>uki,1,UKI,uki,1,https://uapi-group.org/specifications/specs/unified_kernel_image/</literal> <programlisting>uki,1,UKI,uki,1,https://uapi-group.org/specifications/specs/unified_kernel_image/</programlisting>
for UKIs and for UKIs and
<literal>uki-addon,1,UKI Addon,addon,1,https://www.freedesktop.org/software/systemd/man/latest/systemd-stub.html</literal> <programlisting>uki-addon,1,UKI Addon,addon,1,https://www.freedesktop.org/software/systemd/man/latest/systemd-stub.html</programlisting>
for addons will be used, to ensure it is always possible to revoke them. For more information on for addons will be used, to ensure it is always possible to revoke them. For more information on
SBAT see <ulink url="https://github.com/rhboot/shim/blob/main/SBAT.md">Shim documentation</ulink>. SBAT see <ulink url="https://github.com/rhboot/shim/blob/main/SBAT.md">Shim documentation</ulink>.
</para> </para>

View File

@ -289,7 +289,8 @@ int write_string_file_full(
const char *fn, const char *fn,
const char *line, const char *line,
WriteStringFileFlags flags, WriteStringFileFlags flags,
const struct timespec *ts) { const struct timespec *ts,
const char *label_fn) {
bool call_label_ops_post = false, made_file = false; bool call_label_ops_post = false, made_file = false;
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;
@ -321,7 +322,8 @@ int write_string_file_full(
mode_t mode = write_string_file_flags_to_mode(flags); mode_t mode = write_string_file_flags_to_mode(flags);
if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL|WRITE_STRING_FILE_CREATE)) { if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL|WRITE_STRING_FILE_CREATE)) {
r = label_ops_pre(dir_fd, fn, mode); const char *lookup = label_fn ? label_fn : fn;
r = label_ops_pre(dir_fd, lookup, mode);
if (r < 0) if (r < 0)
goto fail; goto fail;

View File

@ -51,12 +51,13 @@ int write_string_stream_full(FILE *f, const char *line, WriteStringFileFlags fla
static inline int write_string_stream(FILE *f, const char *line, WriteStringFileFlags flags) { static inline int write_string_stream(FILE *f, const char *line, WriteStringFileFlags flags) {
return write_string_stream_full(f, line, flags, /* ts= */ NULL); return write_string_stream_full(f, line, flags, /* ts= */ NULL);
} }
int write_string_file_full(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts);
int write_string_file_full(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts, const char *label_fn);
static inline int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) { static inline int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
return write_string_file_full(AT_FDCWD, fn, line, flags, /* ts= */ NULL); return write_string_file_full(AT_FDCWD, fn, line, flags, /* ts= */ NULL, /*label_fn=*/ NULL);
} }
static inline int write_string_file_at(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags) { static inline int write_string_file_at(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags) {
return write_string_file_full(dir_fd, fn, line, flags, /* ts= */ NULL); return write_string_file_full(dir_fd, fn, line, flags, /* ts= */ NULL, /*label_fn=*/ NULL);
} }
int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4); int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4);

View File

@ -1698,7 +1698,8 @@ _public_ int sd_varlink_get_events(sd_varlink *v) {
ret |= EPOLLIN; ret |= EPOLLIN;
if (!v->write_disconnected && if (!v->write_disconnected &&
v->output_buffer_size > 0) (v->output_queue ||
v->output_buffer_size > 0))
ret |= EPOLLOUT; ret |= EPOLLOUT;
return ret; return ret;

View File

@ -1,10 +1,11 @@
# SPDX-License-Identifier: LGPL-2.1-or-later # SPDX-License-Identifier: LGPL-2.1-or-later
systemd_oomd_sources = files( systemd_oomd_sources = files(
'oomd-manager-bus.c',
'oomd-manager.c',
'oomd-util.c',
'oomd.c', 'oomd.c',
'oomd-conf.c',
'oomd-manager.c',
'oomd-manager-bus.c',
'oomd-util.c',
) )
executables += [ executables += [

119
src/oom/oomd-conf.c Normal file
View File

@ -0,0 +1,119 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "conf-parser.h"
#include "log.h"
#include "oomd-conf.h"
#include "oomd-manager.h"
static int arg_swap_used_limit_permyriad = -1;
static int arg_mem_pressure_limit_permyriad = -1;
static usec_t arg_mem_pressure_usec = DEFAULT_MEM_PRESSURE_DURATION_USEC;
static int config_parse_duration(
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) {
usec_t usec, *duration = ASSERT_PTR(data);
int r;
if (isempty(rvalue)) {
*duration = DEFAULT_MEM_PRESSURE_DURATION_USEC;
return 0;
}
r = parse_sec(rvalue, &usec);
if (r < 0)
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
if (usec == 0) {
/* Map zero -> default for backwards compatibility. */
*duration = DEFAULT_MEM_PRESSURE_DURATION_USEC;
return 0;
}
if (usec < 1 * USEC_PER_SEC || usec == USEC_INFINITY)
return log_syntax(
unit,
LOG_WARNING,
filename,
line,
0,
"%s= must be at least 1s and less than infinity, ignoring: %s",
lvalue,
rvalue);
*duration = usec;
return 0;
}
int manager_set_defaults(Manager *m) {
assert(m);
int r;
m->swap_used_limit_permyriad = DEFAULT_SWAP_USED_LIMIT_PERCENT * 100;
r = store_loadavg_fixed_point(DEFAULT_MEM_PRESSURE_LIMIT_PERCENT, 0, &m->default_mem_pressure_limit);
if (r < 0)
return r;
m->default_mem_pressure_duration_usec = DEFAULT_MEM_PRESSURE_DURATION_USEC;
return 0;
}
int manager_parse_config_file(Manager *m) {
assert(m);
unsigned long l, f;
int r;
arg_swap_used_limit_permyriad = -1;
arg_mem_pressure_limit_permyriad = -1;
arg_mem_pressure_usec = DEFAULT_MEM_PRESSURE_DURATION_USEC;
static const ConfigTableItem items[] = {
{ "OOM", "SwapUsedLimit", config_parse_permyriad, 0, &arg_swap_used_limit_permyriad },
{ "OOM", "DefaultMemoryPressureLimit", config_parse_permyriad, 0, &arg_mem_pressure_limit_permyriad },
{ "OOM", "DefaultMemoryPressureDurationSec", config_parse_duration, 0, &arg_mem_pressure_usec },
{}
};
r = config_parse_standard_file_with_dropins(
"systemd/oomd.conf",
"OOM\0",
config_item_table_lookup,
items,
CONFIG_PARSE_WARN,
/* userdata= */ NULL);
if (r < 0)
return r;
m->swap_used_limit_permyriad = arg_swap_used_limit_permyriad >= 0 ?
arg_swap_used_limit_permyriad :
DEFAULT_SWAP_USED_LIMIT_PERCENT * 100;
assert(m->swap_used_limit_permyriad <= 10000);
if (arg_mem_pressure_limit_permyriad >= 0) {
assert(arg_mem_pressure_limit_permyriad <= 10000);
l = arg_mem_pressure_limit_permyriad / 100;
f = arg_mem_pressure_limit_permyriad % 100;
} else {
l = DEFAULT_MEM_PRESSURE_LIMIT_PERCENT;
f = 0;
}
r = store_loadavg_fixed_point(l, f, &m->default_mem_pressure_limit);
if (r < 0)
return r;
m->default_mem_pressure_duration_usec = arg_mem_pressure_usec;
return 0;
}

9
src/oom/oomd-conf.h Normal file
View File

@ -0,0 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "conf-parser.h"
#include "oomd-manager.h"
int manager_set_defaults(Manager *m);
int manager_parse_config_file(Manager *m);

View File

@ -4,15 +4,17 @@
#include "sd-json.h" #include "sd-json.h"
#include "bus-log-control-api.h" #include "bus-log-control-api.h"
#include "bus-util.h"
#include "bus-polkit.h" #include "bus-polkit.h"
#include "bus-util.h"
#include "cgroup-util.h" #include "cgroup-util.h"
#include "daemon-util.h"
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "format-util.h" #include "format-util.h"
#include "json-util.h" #include "json-util.h"
#include "memory-util.h" #include "memory-util.h"
#include "memstream-util.h" #include "memstream-util.h"
#include "oomd-conf.h"
#include "oomd-manager-bus.h" #include "oomd-manager-bus.h"
#include "oomd-manager.h" #include "oomd-manager.h"
#include "path-util.h" #include "path-util.h"
@ -120,6 +122,7 @@ static int process_managed_oom_message(Manager *m, uid_t uid, sd_json_variant *p
if (r < 0 && r != -EEXIST) if (r < 0 && r != -EEXIST)
log_debug_errno(r, "Failed to insert message, ignoring: %m"); log_debug_errno(r, "Failed to insert message, ignoring: %m");
// TODO: Given that these values are updated dynamically on every invocation, it is okay not to handle this as part of reload.
/* Always update the limit in case it was changed. For non-memory pressure detection the value is /* Always update the limit in case it was changed. For non-memory pressure detection the value is
* ignored so always updating it here is not a problem. */ * ignored so always updating it here is not a problem. */
ctx = hashmap_get(monitor_hm, empty_to_root(message.path)); ctx = hashmap_get(monitor_hm, empty_to_root(message.path));
@ -648,6 +651,26 @@ Manager* manager_free(Manager *m) {
return mfree(m); return mfree(m);
} }
static int manager_dispatch_reload_signal(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
int r;
(void) notify_reloading();
r = manager_set_defaults(m);
if (r < 0)
log_warning_errno(r, "Failed to set default values on reload: %m");
r = manager_parse_config_file(m);
if (r < 0)
log_warning_errno(r, "Failed to parse config file on reload: %m");
else
log_info("Config file reloaded.");
(void) sd_notify(/* unset= */ false, NOTIFY_READY);
return 0;
}
int manager_new(Manager **ret) { int manager_new(Manager **ret) {
_cleanup_(manager_freep) Manager *m = NULL; _cleanup_(manager_freep) Manager *m = NULL;
int r; int r;
@ -658,12 +681,24 @@ int manager_new(Manager **ret) {
if (!m) if (!m)
return -ENOMEM; return -ENOMEM;
r = manager_set_defaults(m);
if (r < 0)
log_warning_errno(r, "Failed to set default values on reload: %m");
r = manager_parse_config_file(m);
if (r < 0)
log_warning_errno(r, "Failed to parse configuration file: %m");
r = sd_event_default(&m->event); r = sd_event_default(&m->event);
if (r < 0) if (r < 0)
return r; return r;
(void) sd_event_set_watchdog(m->event, true); (void) sd_event_set_watchdog(m->event, true);
r = sd_event_add_signal(m->event, /* ret_event_source= */ NULL, SIGHUP | SD_EVENT_SIGNAL_PROCMASK, manager_dispatch_reload_signal, m);
if (r < 0)
return r;
r = sd_event_set_signal_exit(m->event, true); r = sd_event_set_signal_exit(m->event, true);
if (r < 0) if (r < 0)
return r; return r;
@ -754,36 +789,14 @@ static int manager_varlink_init(Manager *m, int fd) {
int manager_start( int manager_start(
Manager *m, Manager *m,
bool dry_run, bool dry_run,
int swap_used_limit_permyriad,
int mem_pressure_limit_permyriad,
usec_t mem_pressure_usec,
int fd) { int fd) {
unsigned long l, f;
int r; int r;
assert(m); assert(m);
m->dry_run = dry_run; m->dry_run = dry_run;
m->swap_used_limit_permyriad = swap_used_limit_permyriad >= 0 ? swap_used_limit_permyriad : DEFAULT_SWAP_USED_LIMIT_PERCENT * 100;
assert(m->swap_used_limit_permyriad <= 10000);
if (mem_pressure_limit_permyriad >= 0) {
assert(mem_pressure_limit_permyriad <= 10000);
l = mem_pressure_limit_permyriad / 100;
f = mem_pressure_limit_permyriad % 100;
} else {
l = DEFAULT_MEM_PRESSURE_LIMIT_PERCENT;
f = 0;
}
r = store_loadavg_fixed_point(l, f, &m->default_mem_pressure_limit);
if (r < 0)
return r;
m->default_mem_pressure_duration_usec = mem_pressure_usec;
r = manager_connect_bus(m); r = manager_connect_bus(m);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -66,7 +66,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
int manager_new(Manager **ret); int manager_new(Manager **ret);
int manager_start(Manager *m, bool dry_run, int swap_used_limit_permyriad, int mem_pressure_limit_permyriad, usec_t mem_pressure_usec, int fd); int manager_start(Manager *m, bool dry_run, int fd);
int manager_get_dump_string(Manager *m, char **ret); int manager_get_dump_string(Manager *m, char **ret);

View File

@ -11,6 +11,7 @@
#include "fileio.h" #include "fileio.h"
#include "log.h" #include "log.h"
#include "main-func.h" #include "main-func.h"
#include "oomd-conf.h"
#include "oomd-manager-bus.h" #include "oomd-manager-bus.h"
#include "oomd-manager.h" #include "oomd-manager.h"
#include "parse-util.h" #include "parse-util.h"
@ -19,62 +20,6 @@
#include "signal-util.h" #include "signal-util.h"
static bool arg_dry_run = false; static bool arg_dry_run = false;
static int arg_swap_used_limit_permyriad = -1;
static int arg_mem_pressure_limit_permyriad = -1;
static usec_t arg_mem_pressure_usec = DEFAULT_MEM_PRESSURE_DURATION_USEC;
static int config_parse_duration(
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) {
usec_t usec, *duration = ASSERT_PTR(data);
int r;
if (isempty(rvalue)) {
*duration = DEFAULT_MEM_PRESSURE_DURATION_USEC;
return 0;
}
r = parse_sec(rvalue, &usec);
if (r < 0)
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
if (usec == 0) {
/* Map zero -> default for backwards compatibility. */
*duration = DEFAULT_MEM_PRESSURE_DURATION_USEC;
return 0;
}
if (usec < 1 * USEC_PER_SEC || usec == USEC_INFINITY)
return log_syntax(unit, LOG_WARNING, filename, line, 0, "%s= must be at least 1s and less than infinity, ignoring: %s", lvalue, rvalue);
*duration = usec;
return 0;
}
static int parse_config(void) {
static const ConfigTableItem items[] = {
{ "OOM", "SwapUsedLimit", config_parse_permyriad, 0, &arg_swap_used_limit_permyriad },
{ "OOM", "DefaultMemoryPressureLimit", config_parse_permyriad, 0, &arg_mem_pressure_limit_permyriad },
{ "OOM", "DefaultMemoryPressureDurationSec", config_parse_duration, 0, &arg_mem_pressure_usec },
{}
};
return config_parse_standard_file_with_dropins(
"systemd/oomd.conf",
"OOM\0",
config_item_table_lookup, items,
CONFIG_PARSE_WARN,
/* userdata= */ NULL);
}
static int help(void) { static int help(void) {
_cleanup_free_ char *link = NULL; _cleanup_free_ char *link = NULL;
@ -166,10 +111,6 @@ static int run(int argc, char *argv[]) {
if (r <= 0) if (r <= 0)
return r; return r;
r = parse_config();
if (r < 0)
return r;
/* Do some basic requirement checks for running systemd-oomd. It's not exhaustive as some of the other /* Do some basic requirement checks for running systemd-oomd. It's not exhaustive as some of the other
* requirements do not have a reliable means to check for in code. */ * requirements do not have a reliable means to check for in code. */
@ -211,9 +152,6 @@ static int run(int argc, char *argv[]) {
r = manager_start( r = manager_start(
m, m,
arg_dry_run, arg_dry_run,
arg_swap_used_limit_permyriad,
arg_mem_pressure_limit_permyriad,
arg_mem_pressure_usec,
fd); fd);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to start up daemon: %m"); return log_error_errno(r, "Failed to start up daemon: %m");

View File

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <getopt.h> #include <getopt.h>
#include <linux/loop.h> #include <linux/loop.h>
@ -45,6 +46,7 @@
#include "process-util.h" #include "process-util.h"
#include "rm-rf.h" #include "rm-rf.h"
#include "sort-util.h" #include "sort-util.h"
#include "selinux-util.h"
#include "string-table.h" #include "string-table.h"
#include "string-util.h" #include "string-util.h"
#include "terminal-util.h" #include "terminal-util.h"
@ -899,6 +901,7 @@ static int resolve_mutable_directory(
_cleanup_free_ char *path = NULL, *resolved_path = NULL, *dir_name = NULL; _cleanup_free_ char *path = NULL, *resolved_path = NULL, *dir_name = NULL;
const char *root = arg_root, *base = MUTABLE_EXTENSIONS_BASE_DIR; const char *root = arg_root, *base = MUTABLE_EXTENSIONS_BASE_DIR;
int r; int r;
_cleanup_close_ int atfd = -EBADF;
assert(hierarchy); assert(hierarchy);
assert(ret_resolved_mutable_directory); assert(ret_resolved_mutable_directory);
@ -943,6 +946,14 @@ static int resolve_mutable_directory(
r = mkdir_p(path_in_root, 0700); r = mkdir_p(path_in_root, 0700);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to create a directory '%s': %m", path_in_root); return log_error_errno(r, "Failed to create a directory '%s': %m", path_in_root);
atfd = open(path_in_root, O_DIRECTORY|O_CLOEXEC);
if (atfd < 0)
return log_error_errno(errno, "Failed to open directory '%s': %m", path_in_root);
r = mac_selinux_fix_full(atfd, NULL, hierarchy, 0);
if (r < 0)
return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", path_in_root);
} }
r = chase(path, root, CHASE_PREFIX_ROOT, &resolved_path, NULL); r = chase(path, root, CHASE_PREFIX_ROOT, &resolved_path, NULL);
@ -1289,6 +1300,7 @@ static int mount_overlayfs_with_op(
int r; int r;
const char *top_layer = NULL; const char *top_layer = NULL;
_cleanup_close_ int atfd = -EBADF;
assert(op); assert(op);
assert(overlay_path); assert(overlay_path);
@ -1301,10 +1313,28 @@ static int mount_overlayfs_with_op(
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to make directory '%s': %m", meta_path); return log_error_errno(r, "Failed to make directory '%s': %m", meta_path);
atfd = open(meta_path, O_DIRECTORY|O_CLOEXEC);
if (atfd < 0)
return log_error_errno(errno, "Failed to open directory '%s': %m", meta_path);
r = mac_selinux_fix_full(atfd, NULL, op->hierarchy, 0);
if (r < 0)
return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", meta_path);
if (op->upper_dir && op->work_dir) { if (op->upper_dir && op->work_dir) {
r = mkdir_p(op->work_dir, 0700); r = mkdir_p(op->work_dir, 0700);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to make directory '%s': %m", op->work_dir); return log_error_errno(r, "Failed to make directory '%s': %m", op->work_dir);
_cleanup_close_ int dfd = -EBADF;
dfd = open(op->work_dir, O_DIRECTORY|O_CLOEXEC);
if (dfd < 0)
return log_error_errno(errno, "Failed to open directory '%s': %m", op->work_dir);
r = mac_selinux_fix_full(dfd, NULL, op->hierarchy, 0);
if (r < 0)
return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", op->work_dir);
top_layer = op->upper_dir; top_layer = op->upper_dir;
} else { } else {
assert(!strv_isempty(op->lower_dirs)); assert(!strv_isempty(op->lower_dirs));
@ -1325,7 +1355,7 @@ static int mount_overlayfs_with_op(
return 0; return 0;
} }
static int write_extensions_file(ImageClass image_class, char **extensions, const char *meta_path) { static int write_extensions_file(ImageClass image_class, char **extensions, const char *meta_path, const char *hierarchy) {
_cleanup_free_ char *f = NULL, *buf = NULL; _cleanup_free_ char *f = NULL, *buf = NULL;
int r; int r;
@ -1343,14 +1373,15 @@ static int write_extensions_file(ImageClass image_class, char **extensions, cons
if (!buf) if (!buf)
return log_oom(); return log_oom();
r = write_string_file(f, buf, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755); const char *hierarchy_path = path_join(hierarchy, image_class_info[image_class].dot_directory_name, image_class_info[image_class].short_identifier_plural);
r = write_string_file_full(AT_FDCWD,f, buf, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755|WRITE_STRING_FILE_LABEL, NULL, hierarchy_path);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to write extension meta file '%s': %m", f); return log_error_errno(r, "Failed to write extension meta file '%s': %m", f);
return 0; return 0;
} }
static int write_dev_file(ImageClass image_class, const char *meta_path, const char *overlay_path) { static int write_dev_file(ImageClass image_class, const char *meta_path, const char *overlay_path, const char *hierarchy) {
_cleanup_free_ char *f = NULL; _cleanup_free_ char *f = NULL;
struct stat st; struct stat st;
int r; int r;
@ -1372,14 +1403,15 @@ static int write_dev_file(ImageClass image_class, const char *meta_path, const c
/* Modifying the underlying layers while the overlayfs is mounted is technically undefined, but at /* Modifying the underlying layers while the overlayfs is mounted is technically undefined, but at
* least it won't crash or deadlock, as per the kernel docs about overlayfs: * least it won't crash or deadlock, as per the kernel docs about overlayfs:
* https://www.kernel.org/doc/html/latest/filesystems/overlayfs.html#changes-to-underlying-filesystems */ * https://www.kernel.org/doc/html/latest/filesystems/overlayfs.html#changes-to-underlying-filesystems */
r = write_string_file(f, FORMAT_DEVNUM(st.st_dev), WRITE_STRING_FILE_CREATE); const char *hierarchy_path = path_join(hierarchy, image_class_info[image_class].dot_directory_name, image_class_info[image_class].short_identifier_plural);
r = write_string_file_full(AT_FDCWD, f, FORMAT_DEVNUM(st.st_dev), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_LABEL, NULL, hierarchy_path);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to write '%s': %m", f); return log_error_errno(r, "Failed to write '%s': %m", f);
return 0; return 0;
} }
static int write_work_dir_file(ImageClass image_class, const char *meta_path, const char *work_dir) { static int write_work_dir_file(ImageClass image_class, const char *meta_path, const char *work_dir, const char* hierarchy) {
_cleanup_free_ char *escaped_work_dir_in_root = NULL, *f = NULL; _cleanup_free_ char *escaped_work_dir_in_root = NULL, *f = NULL;
char *work_dir_in_root = NULL; char *work_dir_in_root = NULL;
int r; int r;
@ -1406,7 +1438,8 @@ static int write_work_dir_file(ImageClass image_class, const char *meta_path, co
escaped_work_dir_in_root = cescape(work_dir_in_root); escaped_work_dir_in_root = cescape(work_dir_in_root);
if (!escaped_work_dir_in_root) if (!escaped_work_dir_in_root)
return log_oom(); return log_oom();
r = write_string_file(f, escaped_work_dir_in_root, WRITE_STRING_FILE_CREATE); const char *hierarchy_path = path_join(hierarchy, image_class_info[image_class].dot_directory_name, "work_dir");
r = write_string_file_full(AT_FDCWD, f, escaped_work_dir_in_root, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_LABEL, NULL, hierarchy_path);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to write '%s': %m", f); return log_error_errno(r, "Failed to write '%s': %m", f);
@ -1418,8 +1451,10 @@ static int store_info_in_meta(
char **extensions, char **extensions,
const char *meta_path, const char *meta_path,
const char *overlay_path, const char *overlay_path,
const char *work_dir) { const char *work_dir,
const char *hierarchy) {
_cleanup_free_ char *f = NULL;
_cleanup_close_ int atfd = -EBADF;
int r; int r;
assert(extensions); assert(extensions);
@ -1427,15 +1462,32 @@ static int store_info_in_meta(
assert(overlay_path); assert(overlay_path);
/* work_dir may be NULL */ /* work_dir may be NULL */
r = write_extensions_file(image_class, extensions, meta_path); f = path_join(meta_path, image_class_info[image_class].dot_directory_name);
if (!f)
return log_oom();
r = mkdir_p(f, 0755);
if (r < 0) if (r < 0)
return r; return r;
r = write_dev_file(image_class, meta_path, overlay_path); atfd = open(f, O_DIRECTORY|O_CLOEXEC);
if (atfd < 0)
return log_error_errno(errno, "Failed to open directory '%s': %m", f);
r = mac_selinux_fix_full(atfd, NULL, hierarchy, 0);
if (r < 0)
return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", hierarchy);
r = write_extensions_file(image_class, extensions, meta_path, hierarchy);
if (r < 0) if (r < 0)
return r; return r;
r = write_work_dir_file(image_class, meta_path, work_dir); r = write_dev_file(image_class, meta_path, overlay_path, hierarchy);
if (r < 0)
return r;
r = write_work_dir_file(image_class, meta_path, work_dir, hierarchy);
if (r < 0) if (r < 0)
return r; return r;
@ -1501,6 +1553,8 @@ static int merge_hierarchy(
assert(overlay_path); assert(overlay_path);
assert(workspace_path); assert(workspace_path);
mac_selinux_init();
r = determine_used_extensions(hierarchy, paths, &used_paths, &extensions_used); r = determine_used_extensions(hierarchy, paths, &used_paths, &extensions_used);
if (r < 0) if (r < 0)
return r; return r;
@ -1528,7 +1582,7 @@ static int merge_hierarchy(
if (r < 0) if (r < 0)
return r; return r;
r = store_info_in_meta(image_class, extensions, meta_path, overlay_path, op->work_dir); r = store_info_in_meta(image_class, extensions, meta_path, overlay_path, op->work_dir, op->hierarchy);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -29,7 +29,7 @@ static int apply_timestamp(const char *path, struct timespec *ts) {
timespec_load_nsec(ts)) < 0) timespec_load_nsec(ts)) < 0)
return log_oom(); return log_oom();
r = write_string_file_full(AT_FDCWD, path, message, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL, ts); r = write_string_file_full(AT_FDCWD, path, message, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL, ts, NULL);
if (r == -EROFS) if (r == -EROFS)
log_debug_errno(r, "Cannot create \"%s\", file system is read-only.", path); log_debug_errno(r, "Cannot create \"%s\", file system is read-only.", path);
else if (r < 0) else if (r < 0)

View File

@ -22,6 +22,11 @@ trap at_exit EXIT
systemctl service-log-level systemd-machined debug systemctl service-log-level systemd-machined debug
systemctl service-log-level systemd-importd debug systemctl service-log-level systemd-importd debug
# per request in https://github.com/systemd/systemd/pull/35117
systemctl edit --runtime --stdin 'systemd-nspawn@.service' --drop-in=debug.conf <<EOF
[Service]
Environment=SYSTEMD_LOG_LEVEL=debug
EOF
# Mount temporary directory over /var/lib/machines to not pollute the image # Mount temporary directory over /var/lib/machines to not pollute the image
mkdir -p /var/lib/machines mkdir -p /var/lib/machines
@ -278,13 +283,13 @@ varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List
# sending TRAP signal # sending TRAP signal
rm -f /var/lib/machines/long-running/trap rm -f /var/lib/machines/long-running/trap
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Kill '{"name":"long-running", "whom": "leader", "signal": 5}' varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Kill '{"name":"long-running", "whom": "leader", "signal": 5}'
timeout 30 bash -c "until test -e /var/lib/machines/long-running/trap; do sleep .5; done" timeout 120 bash -c "until test -e /var/lib/machines/long-running/trap; do sleep .5; done"
# test io.systemd.Machine.Terminate # test io.systemd.Machine.Terminate
long_running_machine_start long_running_machine_start
rm -f /var/lib/machines/long-running/terminate rm -f /var/lib/machines/long-running/terminate
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Terminate '{"name":"long-running"}' varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Terminate '{"name":"long-running"}'
timeout 10 bash -c "until test -e /var/lib/machines/long-running/terminate; do sleep .5; done" timeout 30 bash -c "until test -e /var/lib/machines/long-running/terminate; do sleep .5; done"
timeout 30 bash -c "while varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{\"name\":\"long-running\"}'; do sleep 0.5; done" timeout 30 bash -c "while varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{\"name\":\"long-running\"}'; do sleep 0.5; done"
# test io.systemd.Machine.Register # test io.systemd.Machine.Register
@ -356,7 +361,7 @@ journalctl --sync
machinectl terminate container-without-os-release machinectl terminate container-without-os-release
machinectl terminate long-running machinectl terminate long-running
# wait for the container being stopped, otherwise acquiring image metadata by io.systemd.MachineImage.List may fail in the below. # wait for the container being stopped, otherwise acquiring image metadata by io.systemd.MachineImage.List may fail in the below.
timeout 10 bash -c "while machinectl status long-running &>/dev/null; do sleep .5; done" timeout 30 bash -c "while machinectl status long-running &>/dev/null; do sleep .5; done"
systemctl kill --signal=KILL systemd-nspawn@long-running.service || : systemctl kill --signal=KILL systemd-nspawn@long-running.service || :
(ip addr show lo | grep -q 192.168.1.100) || ip address add 192.168.1.100/24 dev lo (ip addr show lo | grep -q 192.168.1.100) || ip address add 192.168.1.100/24 dev lo

View File

@ -264,6 +264,40 @@ EOF
systemctl daemon-reload systemctl daemon-reload
} }
testcase_reload() {
# Check if the oomd.conf drop-in config is loaded.
assert_in 'Swap Used Limit: 90.00%' "$(oomctl)"
assert_in 'Default Memory Pressure Limit: 60.00%' "$(oomctl)"
assert_in 'Default Memory Pressure Duration: 2s' "$(oomctl)"
# Test oomd reload
mkdir -p /run/systemd/oomd.conf.d/
{
echo "[OOM]"
echo "SwapUsedLimit=80%"
echo "DefaultMemoryPressureLimit=55%"
echo "DefaultMemoryPressureDurationSec=5s"
} >/run/systemd/oomd.conf.d/99-oomd-test.conf
systemctl reload systemd-oomd.service
assert_in 'Swap Used Limit: 80.00%' "$(oomctl)"
assert_in 'Default Memory Pressure Limit: 55.00%' "$(oomctl)"
assert_in 'Default Memory Pressure Duration: 5s' "$(oomctl)"
# Set back to default via reload
mkdir -p /run/systemd/oomd.conf.d/
{
echo "[OOM]"
echo "DefaultMemoryPressureDurationSec=2s"
} >/run/systemd/oomd.conf.d/99-oomd-test.conf
systemctl reload systemd-oomd.service
assert_in 'Swap Used Limit: 90.00%' "$(oomctl)"
assert_in 'Default Memory Pressure Limit: 60.00%' "$(oomctl)"
assert_in 'Default Memory Pressure Duration: 2s' "$(oomctl)"
}
run_testcases run_testcases
systemd-analyze log-level info systemd-analyze log-level info

View File

@ -53,7 +53,7 @@ RestrictSUIDSGID=yes
SystemCallArchitectures=native SystemCallArchitectures=native
SystemCallErrorNumber=EPERM SystemCallErrorNumber=EPERM
SystemCallFilter=@system-service SystemCallFilter=@system-service
Type=notify Type=notify-reload
User=systemd-oom User=systemd-oom
{{SERVICE_WATCHDOG}} {{SERVICE_WATCHDOG}}