core: add WantsMountsFor=

This is the equivalent of RequiresMountsFor=, but adds Wants= instead
of Requires=. It will be useful for example for the autogenerated
systemd-cryptsetup units.

Fixes https://github.com/systemd/systemd/issues/11646
This commit is contained in:
Luca Boccassi
2023-11-29 11:04:59 +00:00
parent 5fae156103
commit 9e615fa3aa
22 changed files with 227 additions and 120 deletions
+7
View File
@@ -1979,6 +1979,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as RequiresMountsFor = ['...', ...]; readonly as RequiresMountsFor = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as WantsMountsFor = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as Documentation = ['...', ...]; readonly as Documentation = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s Description = '...'; readonly s Description = '...';
@@ -2135,6 +2137,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<!--property SliceOf is not documented!--> <!--property SliceOf is not documented!-->
<!--property WantsMountsFor is not documented!-->
<!--property FreezerState is not documented!--> <!--property FreezerState is not documented!-->
<!--property DropInPaths is not documented!--> <!--property DropInPaths is not documented!-->
@@ -2295,6 +2299,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<variablelist class="dbus-property" generated="True" extra-ref="RequiresMountsFor"/> <variablelist class="dbus-property" generated="True" extra-ref="RequiresMountsFor"/>
<variablelist class="dbus-property" generated="True" extra-ref="WantsMountsFor"/>
<variablelist class="dbus-property" generated="True" extra-ref="Documentation"/> <variablelist class="dbus-property" generated="True" extra-ref="Documentation"/>
<variablelist class="dbus-property" generated="True" extra-ref="Description"/> <variablelist class="dbus-property" generated="True" extra-ref="Description"/>
@@ -11829,6 +11835,7 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
<varname>ActivationDetails</varname> were added in version 252.</para> <varname>ActivationDetails</varname> were added in version 252.</para>
<para><function>QueueSignal()</function> was added in version 254.</para> <para><function>QueueSignal()</function> was added in version 254.</para>
<para><varname>SurviveFinalKillSignal</varname> was added in version 255.</para> <para><varname>SurviveFinalKillSignal</varname> was added in version 255.</para>
<para><varname>WantsMountsFor</varname> was added in version 256.</para>
</refsect2> </refsect2>
<refsect2> <refsect2>
<title>Service Unit Objects</title> <title>Service Unit Objects</title>
+5 -4
View File
@@ -255,13 +255,14 @@
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><option>x-systemd.wants-mounts-for=</option></term>
<term><option>x-systemd.requires-mounts-for=</option></term> <term><option>x-systemd.requires-mounts-for=</option></term>
<listitem><para>Configures a <listitem><para>Configures a
<varname>RequiresMountsFor=</varname> dependency between the <varname>RequiresMountsFor=</varname> or <varname>WantsMountsFor=</varname>
created mount unit and other mount units. The argument must be dependency between the created mount unit and other mount units. The
an absolute path. This option may be specified more than once. argument must be an absolute path. This option may be specified more than
See <varname>RequiresMountsFor=</varname> in once. See <varname>RequiresMountsFor=</varname> or <varname>WantsMountsFor=</varname> in
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details.</para> for details.</para>
+10
View File
@@ -919,6 +919,16 @@
<xi:include href="version-info.xml" xpointer="v201"/></listitem> <xi:include href="version-info.xml" xpointer="v201"/></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>WantsMountsFor=</varname></term>
<listitem><para>Same as <varname>RequiresMountsFor=</varname>,
but adds dependencies of type <varname>Wants=</varname> instead
of <varname>Requires=</varname>.</para>
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>OnSuccessJobMode=</varname></term> <term><varname>OnSuccessJobMode=</varname></term>
<term><varname>OnFailureJobMode=</varname></term> <term><varname>OnFailureJobMode=</varname></term>
+1 -1
View File
@@ -126,7 +126,7 @@ static int automount_add_mount_dependencies(Automount *a) {
if (r < 0) if (r < 0)
return r; return r;
return unit_require_mounts_for(UNIT(a), parent, UNIT_DEPENDENCY_IMPLICIT); return unit_add_mounts_for(UNIT(a), parent, UNIT_DEPENDENCY_IMPLICIT, UNIT_MOUNT_REQUIRES);
} }
static int automount_add_default_dependencies(Automount *a) { static int automount_add_default_dependencies(Automount *a) {
+6 -5
View File
@@ -177,7 +177,7 @@ static int property_get_dependencies(
return sd_bus_message_close_container(reply); return sd_bus_message_close_container(reply);
} }
static int property_get_requires_mounts_for( static int property_get_mounts_for(
sd_bus *bus, sd_bus *bus,
const char *path, const char *path,
const char *interface, const char *interface,
@@ -879,7 +879,8 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("StopPropagatedFrom", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("StopPropagatedFrom", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SliceOf", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SliceOf", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RequiresMountsFor", "as", property_get_requires_mounts_for, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RequiresMountsFor", "as", property_get_mounts_for, offsetof(Unit, mounts_for[UNIT_MOUNT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("WantsMountsFor", "as", property_get_mounts_for, offsetof(Unit, mounts_for[UNIT_MOUNT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("AccessSELinuxContext", "s", NULL, offsetof(Unit, access_selinux_context), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("AccessSELinuxContext", "s", NULL, offsetof(Unit, access_selinux_context), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -2308,7 +2309,7 @@ static int bus_unit_set_transient_property(
return 1; return 1;
} else if (streq(name, "RequiresMountsFor")) { } else if (STR_IN_SET(name, "RequiresMountsFor", "WantsMountsFor")) {
_cleanup_strv_free_ char **l = NULL; _cleanup_strv_free_ char **l = NULL;
r = sd_bus_message_read_strv(message, &l); r = sd_bus_message_read_strv(message, &l);
@@ -2328,9 +2329,9 @@ static int bus_unit_set_transient_property(
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path specified in %s is not normalized: %s", name, *p); return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path specified in %s is not normalized: %s", name, *p);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) { if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
r = unit_require_mounts_for(u, *p, UNIT_DEPENDENCY_FILE); r = unit_add_mounts_for(u, *p, UNIT_DEPENDENCY_FILE, unit_mount_dependency_type_from_string(name));
if (r < 0) if (r < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to add required mount \"%s\": %m", *p); return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to add requested mount \"%s\": %m", *p);
unit_write_settingf(u, flags, name, "%s=%s", name, *p); unit_write_settingf(u, flags, name, "%s=%s", name, *p);
} }
+2 -1
View File
@@ -309,7 +309,8 @@ Unit.PartOf, config_parse_unit_deps,
Unit.JoinsNamespaceOf, config_parse_unit_deps, UNIT_JOINS_NAMESPACE_OF, 0 Unit.JoinsNamespaceOf, config_parse_unit_deps, UNIT_JOINS_NAMESPACE_OF, 0
Unit.RequiresOverridable, config_parse_obsolete_unit_deps, UNIT_REQUIRES, 0 Unit.RequiresOverridable, config_parse_obsolete_unit_deps, UNIT_REQUIRES, 0
Unit.RequisiteOverridable, config_parse_obsolete_unit_deps, UNIT_REQUISITE, 0 Unit.RequisiteOverridable, config_parse_obsolete_unit_deps, UNIT_REQUISITE, 0
Unit.RequiresMountsFor, config_parse_unit_requires_mounts_for, 0, 0 Unit.RequiresMountsFor, config_parse_unit_mounts_for, 0, 0
Unit.WantsMountsFor, config_parse_unit_mounts_for, 0, 0
Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Unit, stop_when_unneeded) Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Unit, stop_when_unneeded)
Unit.RefuseManualStart, config_parse_bool, 0, offsetof(Unit, refuse_manual_start) Unit.RefuseManualStart, config_parse_bool, 0, offsetof(Unit, refuse_manual_start)
Unit.RefuseManualStop, config_parse_bool, 0, offsetof(Unit, refuse_manual_stop) Unit.RefuseManualStop, config_parse_bool, 0, offsetof(Unit, refuse_manual_stop)
+5 -5
View File
@@ -3152,7 +3152,7 @@ int config_parse_unit_condition_string(
return 0; return 0;
} }
int config_parse_unit_requires_mounts_for( int config_parse_unit_mounts_for(
const char *unit, const char *unit,
const char *filename, const char *filename,
unsigned line, unsigned line,
@@ -3171,6 +3171,7 @@ int config_parse_unit_requires_mounts_for(
assert(lvalue); assert(lvalue);
assert(rvalue); assert(rvalue);
assert(data); assert(data);
assert(STR_IN_SET(lvalue, "RequiresMountsFor", "WantsMountsFor"));
for (const char *p = rvalue;;) { for (const char *p = rvalue;;) {
_cleanup_free_ char *word = NULL, *resolved = NULL; _cleanup_free_ char *word = NULL, *resolved = NULL;
@@ -3196,9 +3197,9 @@ int config_parse_unit_requires_mounts_for(
if (r < 0) if (r < 0)
continue; continue;
r = unit_require_mounts_for(u, resolved, UNIT_DEPENDENCY_FILE); r = unit_add_mounts_for(u, resolved, UNIT_DEPENDENCY_FILE, unit_mount_dependency_type_from_string(lvalue));
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to add required mount '%s', ignoring: %m", resolved); log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to add requested mount '%s', ignoring: %m", resolved);
continue; continue;
} }
} }
@@ -6301,8 +6302,7 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_nsec, "NANOSECONDS" }, { config_parse_nsec, "NANOSECONDS" },
{ config_parse_namespace_path_strv, "PATH [...]" }, { config_parse_namespace_path_strv, "PATH [...]" },
{ config_parse_bind_paths, "PATH[:PATH[:OPTIONS]] [...]" }, { config_parse_bind_paths, "PATH[:PATH[:OPTIONS]] [...]" },
{ config_parse_unit_requires_mounts_for, { config_parse_unit_mounts_for, "PATH [...]" },
"PATH [...]" },
{ config_parse_exec_mount_propagation_flag, { config_parse_exec_mount_propagation_flag,
"MOUNTFLAG" }, "MOUNTFLAG" },
{ config_parse_unit_string_printf, "STRING" }, { config_parse_unit_string_printf, "STRING" },
+1 -1
View File
@@ -71,7 +71,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_unit_condition_string);
CONFIG_PARSER_PROTOTYPE(config_parse_kill_mode); CONFIG_PARSER_PROTOTYPE(config_parse_kill_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_notify_access); CONFIG_PARSER_PROTOTYPE(config_parse_notify_access);
CONFIG_PARSER_PROTOTYPE(config_parse_emergency_action); CONFIG_PARSER_PROTOTYPE(config_parse_emergency_action);
CONFIG_PARSER_PROTOTYPE(config_parse_unit_requires_mounts_for); CONFIG_PARSER_PROTOTYPE(config_parse_unit_mounts_for);
CONFIG_PARSER_PROTOTYPE(config_parse_syscall_filter); CONFIG_PARSER_PROTOTYPE(config_parse_syscall_filter);
CONFIG_PARSER_PROTOTYPE(config_parse_syscall_archs); CONFIG_PARSER_PROTOTYPE(config_parse_syscall_archs);
CONFIG_PARSER_PROTOTYPE(config_parse_syscall_errno); CONFIG_PARSER_PROTOTYPE(config_parse_syscall_errno);
+7 -4
View File
@@ -1691,8 +1691,10 @@ Manager* manager_free(Manager *m) {
unit_defaults_done(&m->defaults); unit_defaults_done(&m->defaults);
assert(hashmap_isempty(m->units_requiring_mounts_for)); FOREACH_ARRAY(map, m->units_needing_mounts_for, _UNIT_MOUNT_DEPENDENCY_TYPE_MAX) {
hashmap_free(m->units_requiring_mounts_for); assert(hashmap_isempty(*map));
hashmap_free(*map);
}
hashmap_free(m->uid_refs); hashmap_free(m->uid_refs);
hashmap_free(m->gid_refs); hashmap_free(m->gid_refs);
@@ -4478,14 +4480,15 @@ void manager_status_printf(Manager *m, StatusType type, const char *status, cons
va_end(ap); va_end(ap);
} }
Set* manager_get_units_requiring_mounts_for(Manager *m, const char *path) { Set* manager_get_units_needing_mounts_for(Manager *m, const char *path, UnitMountDependencyType t) {
assert(m); assert(m);
assert(path); assert(path);
assert(t >= 0 && t < _UNIT_MOUNT_DEPENDENCY_TYPE_MAX);
if (path_equal(path, "/")) if (path_equal(path, "/"))
path = ""; path = "";
return hashmap_get(m->units_requiring_mounts_for, path); return hashmap_get(m->units_needing_mounts_for[t], path);
} }
int manager_update_failed_units(Manager *m, Unit *u, bool failed) { int manager_update_failed_units(Manager *m, Unit *u, bool failed) {
+5 -5
View File
@@ -137,6 +137,7 @@ typedef enum WatchdogType {
#include "path-lookup.h" #include "path-lookup.h"
#include "show-status.h" #include "show-status.h"
#include "unit-name.h" #include "unit-name.h"
#include "unit.h"
typedef enum ManagerTestRunFlags { typedef enum ManagerTestRunFlags {
MANAGER_TEST_NORMAL = 0, /* run normally */ MANAGER_TEST_NORMAL = 0, /* run normally */
@@ -438,10 +439,9 @@ struct Manager {
/* This is true before and after switching root. */ /* This is true before and after switching root. */
bool switching_root; bool switching_root;
/* This maps all possible path prefixes to the units needing /* These map all possible path prefixes to the units needing them. They are hashmaps with a path
* them. It's a hashmap with a path string as key and a Set as * string as key, and a Set as value where Unit objects are contained. */
* value where Unit objects are contained. */ Hashmap *units_needing_mounts_for[_UNIT_MOUNT_DEPENDENCY_TYPE_MAX];
Hashmap *units_requiring_mounts_for;
/* Used for processing polkit authorization responses */ /* Used for processing polkit authorization responses */
Hashmap *polkit_registry; Hashmap *polkit_registry;
@@ -596,7 +596,7 @@ double manager_get_progress(Manager *m);
void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) _printf_(4,5); void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) _printf_(4,5);
Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path); Set* manager_get_units_needing_mounts_for(Manager *m, const char *path, UnitMountDependencyType t);
ManagerState manager_state(Manager *m); ManagerState manager_state(Manager *m);
+28 -17
View File
@@ -281,8 +281,6 @@ static int update_parameters_proc_self_mountinfo(
static int mount_add_mount_dependencies(Mount *m) { static int mount_add_mount_dependencies(Mount *m) {
MountParameters *pm; MountParameters *pm;
Unit *other;
Set *s;
int r; int r;
assert(m); assert(m);
@@ -296,7 +294,7 @@ static int mount_add_mount_dependencies(Mount *m) {
if (r < 0) if (r < 0)
return r; return r;
r = unit_require_mounts_for(UNIT(m), parent, UNIT_DEPENDENCY_IMPLICIT); r = unit_add_mounts_for(UNIT(m), parent, UNIT_DEPENDENCY_IMPLICIT, UNIT_MOUNT_REQUIRES);
if (r < 0) if (r < 0)
return r; return r;
} }
@@ -308,30 +306,43 @@ static int mount_add_mount_dependencies(Mount *m) {
path_is_absolute(pm->what) && path_is_absolute(pm->what) &&
(mount_is_bind(pm) || mount_is_loop(pm) || !mount_is_network(pm))) { (mount_is_bind(pm) || mount_is_loop(pm) || !mount_is_network(pm))) {
r = unit_require_mounts_for(UNIT(m), pm->what, UNIT_DEPENDENCY_FILE); r = unit_add_mounts_for(UNIT(m), pm->what, UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES);
if (r < 0) if (r < 0)
return r; return r;
} }
/* Adds in dependencies to other units that use this path or paths further down in the hierarchy */ /* Adds in dependencies to other units that use this path or paths further down in the hierarchy */
s = manager_get_units_requiring_mounts_for(UNIT(m)->manager, m->where); for (UnitMountDependencyType t = 0; t < _UNIT_MOUNT_DEPENDENCY_TYPE_MAX; ++t) {
SET_FOREACH(other, s) { Unit *other;
Set *s = manager_get_units_needing_mounts_for(UNIT(m)->manager, m->where, t);
if (other->load_state != UNIT_LOADED) SET_FOREACH(other, s) {
continue; if (other->load_state != UNIT_LOADED)
continue;
if (other == UNIT(m)) if (other == UNIT(m))
continue; continue;
r = unit_add_dependency(other, UNIT_AFTER, UNIT(m), true, UNIT_DEPENDENCY_PATH); r = unit_add_dependency(
if (r < 0) other,
return r; UNIT_AFTER,
UNIT(m),
if (UNIT(m)->fragment_path) { /* add_reference= */ true,
/* If we have fragment configuration, then make this dependency required */ UNIT_DEPENDENCY_PATH);
r = unit_add_dependency(other, UNIT_REQUIRES, UNIT(m), true, UNIT_DEPENDENCY_PATH);
if (r < 0) if (r < 0)
return r; return r;
if (UNIT(m)->fragment_path) {
/* If we have fragment configuration, then make this dependency required/wanted */
r = unit_add_dependency(
other,
unit_mount_dependency_type_to_dependency_type(t),
UNIT(m),
/* add_reference= */ true,
UNIT_DEPENDENCY_PATH);
if (r < 0)
return r;
}
} }
} }
+1 -1
View File
@@ -309,7 +309,7 @@ static int path_add_mount_dependencies(Path *p) {
assert(p); assert(p);
LIST_FOREACH(spec, s, p->specs) { LIST_FOREACH(spec, s, p->specs) {
r = unit_require_mounts_for(UNIT(p), s->path, UNIT_DEPENDENCY_FILE); r = unit_add_mounts_for(UNIT(p), s->path, UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES);
if (r < 0) if (r < 0)
return r; return r;
} }
+1 -1
View File
@@ -221,7 +221,7 @@ static int socket_add_mount_dependencies(Socket *s) {
if (!path) if (!path)
continue; continue;
r = unit_require_mounts_for(UNIT(s), path, UNIT_DEPENDENCY_FILE); r = unit_add_mounts_for(UNIT(s), path, UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES);
if (r < 0) if (r < 0)
return r; return r;
} }
+1 -1
View File
@@ -321,7 +321,7 @@ static int swap_add_extras(Swap *s) {
return r; return r;
} }
r = unit_require_mounts_for(UNIT(s), s->what, UNIT_DEPENDENCY_IMPLICIT); r = unit_add_mounts_for(UNIT(s), s->what, UNIT_DEPENDENCY_IMPLICIT, UNIT_MOUNT_REQUIRES);
if (r < 0) if (r < 0)
return r; return r;
+1 -1
View File
@@ -141,7 +141,7 @@ static int timer_setup_persistent(Timer *t) {
if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) { if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers", UNIT_DEPENDENCY_FILE); r = unit_add_mounts_for(UNIT(t), "/var/lib/systemd/timers", UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES);
if (r < 0) if (r < 0)
return r; return r;
+15 -10
View File
@@ -831,21 +831,26 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
} }
} }
if (!hashmap_isempty(u->requires_mounts_for)) { for (UnitMountDependencyType type = 0; type < _UNIT_MOUNT_DEPENDENCY_TYPE_MAX; type++)
UnitDependencyInfo di; if (!hashmap_isempty(u->mounts_for[type])) {
const char *path; UnitDependencyInfo di;
const char *path;
HASHMAP_FOREACH_KEY(di.data, path, u->requires_mounts_for) { HASHMAP_FOREACH_KEY(di.data, path, u->mounts_for[type]) {
bool space = false; bool space = false;
fprintf(f, "%s\tRequiresMountsFor: %s (", prefix, path); fprintf(f,
"%s\t%s: %s (",
prefix,
unit_mount_dependency_type_to_string(type),
path);
print_unit_dependency_mask(f, "origin", di.origin_mask, &space); print_unit_dependency_mask(f, "origin", di.origin_mask, &space);
print_unit_dependency_mask(f, "destination", di.destination_mask, &space); print_unit_dependency_mask(f, "destination", di.destination_mask, &space);
fputs(")\n", f); fputs(")\n", f);
}
} }
}
if (u->load_state == UNIT_LOADED) { if (u->load_state == UNIT_LOADED) {
+102 -54
View File
@@ -689,38 +689,39 @@ static void unit_remove_transient(Unit *u) {
} }
} }
static void unit_free_requires_mounts_for(Unit *u) { static void unit_free_mounts_for(Unit *u) {
assert(u); assert(u);
for (;;) { for (UnitMountDependencyType t = 0; t < _UNIT_MOUNT_DEPENDENCY_TYPE_MAX; ++t) {
_cleanup_free_ char *path = NULL; for (;;) {
_cleanup_free_ char *path = NULL;
path = hashmap_steal_first_key(u->mounts_for[t]);
if (!path)
break;
path = hashmap_steal_first_key(u->requires_mounts_for);
if (!path)
break;
else {
char s[strlen(path) + 1]; char s[strlen(path) + 1];
PATH_FOREACH_PREFIX_MORE(s, path) { PATH_FOREACH_PREFIX_MORE(s, path) {
char *y; char *y;
Set *x; Set *x;
x = hashmap_get2(u->manager->units_requiring_mounts_for, s, (void**) &y); x = hashmap_get2(u->manager->units_needing_mounts_for[t], s, (void**) &y);
if (!x) if (!x)
continue; continue;
(void) set_remove(x, u); (void) set_remove(x, u);
if (set_isempty(x)) { if (set_isempty(x)) {
(void) hashmap_remove(u->manager->units_requiring_mounts_for, y); assert_se(hashmap_remove(u->manager->units_needing_mounts_for[t], y));
free(y); free(y);
set_free(x); set_free(x);
} }
} }
} }
}
u->requires_mounts_for = hashmap_free(u->requires_mounts_for); u->mounts_for[t] = hashmap_free(u->mounts_for[t]);
}
} }
static void unit_done(Unit *u) { static void unit_done(Unit *u) {
@@ -769,7 +770,7 @@ Unit* unit_free(Unit *u) {
u->deserialized_refs = strv_free(u->deserialized_refs); u->deserialized_refs = strv_free(u->deserialized_refs);
u->pending_freezer_invocation = sd_bus_message_unref(u->pending_freezer_invocation); u->pending_freezer_invocation = sd_bus_message_unref(u->pending_freezer_invocation);
unit_free_requires_mounts_for(u); unit_free_mounts_for(u);
SET_FOREACH(t, u->aliases) SET_FOREACH(t, u->aliases)
hashmap_remove_value(u->manager->units, t, u); hashmap_remove_value(u->manager->units, t, u);
@@ -1278,19 +1279,19 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
/* Unlike unit_add_dependency() or friends, this always returns 0 on success. */ /* Unlike unit_add_dependency() or friends, this always returns 0 on success. */
if (c->working_directory && !c->working_directory_missing_ok) { if (c->working_directory && !c->working_directory_missing_ok) {
r = unit_require_mounts_for(u, c->working_directory, UNIT_DEPENDENCY_FILE); r = unit_add_mounts_for(u, c->working_directory, UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES);
if (r < 0) if (r < 0)
return r; return r;
} }
if (c->root_directory) { if (c->root_directory) {
r = unit_require_mounts_for(u, c->root_directory, UNIT_DEPENDENCY_FILE); r = unit_add_mounts_for(u, c->root_directory, UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES);
if (r < 0) if (r < 0)
return r; return r;
} }
if (c->root_image) { if (c->root_image) {
r = unit_require_mounts_for(u, c->root_image, UNIT_DEPENDENCY_FILE); r = unit_add_mounts_for(u, c->root_image, UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES);
if (r < 0) if (r < 0)
return r; return r;
} }
@@ -1306,7 +1307,7 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
if (!p) if (!p)
return -ENOMEM; return -ENOMEM;
r = unit_require_mounts_for(u, p, UNIT_DEPENDENCY_FILE); r = unit_add_mounts_for(u, p, UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES);
if (r < 0) if (r < 0)
return r; return r;
} }
@@ -1335,7 +1336,7 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
if (r < 0) if (r < 0)
return r; return r;
r = unit_require_mounts_for(u, "/var/tmp", UNIT_DEPENDENCY_FILE); r = unit_add_mounts_for(u, "/var/tmp", UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES);
if (r < 0) if (r < 0)
return r; return r;
@@ -1536,51 +1537,72 @@ static int unit_add_slice_dependencies(Unit *u) {
} }
static int unit_add_mount_dependencies(Unit *u) { static int unit_add_mount_dependencies(Unit *u) {
UnitDependencyInfo di;
const char *path;
bool changed = false; bool changed = false;
int r; int r;
assert(u); assert(u);
HASHMAP_FOREACH_KEY(di.data, path, u->requires_mounts_for) { for (UnitMountDependencyType t = 0; t < _UNIT_MOUNT_DEPENDENCY_TYPE_MAX; ++t) {
char prefix[strlen(path) + 1]; UnitDependencyInfo di;
const char *path;
PATH_FOREACH_PREFIX_MORE(prefix, path) { HASHMAP_FOREACH_KEY(di.data, path, u->mounts_for[t]) {
_cleanup_free_ char *p = NULL;
Unit *m;
r = unit_name_from_path(prefix, ".mount", &p); char prefix[strlen(ASSERT_PTR(path)) + 1];
if (r == -EINVAL)
continue; /* If the path cannot be converted to a mount unit name, then it's
* not manageable as a unit by systemd, and hence we don't need a
* dependency on it. Let's thus silently ignore the issue. */
if (r < 0)
return r;
m = manager_get_unit(u->manager, p); PATH_FOREACH_PREFIX_MORE(prefix, path) {
if (!m) { _cleanup_free_ char *p = NULL;
/* Make sure to load the mount unit if it exists. If so the dependencies on Unit *m;
* this unit will be added later during the loading of the mount unit. */
(void) manager_load_unit_prepare(u->manager, p, NULL, NULL, &m);
continue;
}
if (m == u)
continue;
if (m->load_state != UNIT_LOADED) r = unit_name_from_path(prefix, ".mount", &p);
continue; if (r == -EINVAL)
continue; /* If the path cannot be converted to a mount unit name,
* then it's not manageable as a unit by systemd, and
* hence we don't need a dependency on it. Let's thus
* silently ignore the issue. */
if (r < 0)
return r;
r = unit_add_dependency(u, UNIT_AFTER, m, true, di.origin_mask); m = manager_get_unit(u->manager, p);
if (r < 0) if (!m) {
return r; /* Make sure to load the mount unit if it exists. If so the
changed = changed || r > 0; * dependencies on this unit will be added later during the loading
* of the mount unit. */
(void) manager_load_unit_prepare(
u->manager,
p,
/* path= */NULL,
/* e= */NULL,
&m);
continue;
}
if (m == u)
continue;
if (m->fragment_path) { if (m->load_state != UNIT_LOADED)
r = unit_add_dependency(u, UNIT_REQUIRES, m, true, di.origin_mask); continue;
r = unit_add_dependency(
u,
UNIT_AFTER,
m,
/* add_reference= */ true,
di.origin_mask);
if (r < 0) if (r < 0)
return r; return r;
changed = changed || r > 0; changed = changed || r > 0;
if (m->fragment_path) {
r = unit_add_dependency(
u,
unit_mount_dependency_type_to_dependency_type(t),
m,
/* add_reference= */ true,
di.origin_mask);
if (r < 0)
return r;
changed = changed || r > 0;
}
} }
} }
} }
@@ -4942,11 +4964,16 @@ int unit_kill_context(
return wait_for_exit; return wait_for_exit;
} }
int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask) { int unit_add_mounts_for(Unit *u, const char *path, UnitDependencyMask mask, UnitMountDependencyType type) {
Hashmap **unit_map, **manager_map;
int r; int r;
assert(u); assert(u);
assert(path); assert(path);
assert(type >= 0 && type < _UNIT_MOUNT_DEPENDENCY_TYPE_MAX);
unit_map = &u->mounts_for[type];
manager_map = &u->manager->units_needing_mounts_for[type];
/* Registers a unit for requiring a certain path and all its prefixes. We keep a hashtable of these /* Registers a unit for requiring a certain path and all its prefixes. We keep a hashtable of these
* paths in the unit (from the path to the UnitDependencyInfo structure indicating how to the * paths in the unit (from the path to the UnitDependencyInfo structure indicating how to the
@@ -4956,7 +4983,7 @@ int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask)
if (!path_is_absolute(path)) if (!path_is_absolute(path))
return -EINVAL; return -EINVAL;
if (hashmap_contains(u->requires_mounts_for, path)) /* Exit quickly if the path is already covered. */ if (hashmap_contains(*unit_map, path)) /* Exit quickly if the path is already covered. */
return 0; return 0;
/* Use the canonical form of the path as the stored key. We call path_is_normalized() /* Use the canonical form of the path as the stored key. We call path_is_normalized()
@@ -4975,7 +5002,7 @@ int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask)
.origin_mask = mask .origin_mask = mask
}; };
r = hashmap_ensure_put(&u->requires_mounts_for, &path_hash_ops, p, di.data); r = hashmap_ensure_put(unit_map, &path_hash_ops, p, di.data);
if (r < 0) if (r < 0)
return r; return r;
assert(r > 0); assert(r > 0);
@@ -4985,11 +5012,11 @@ int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask)
PATH_FOREACH_PREFIX_MORE(prefix, path) { PATH_FOREACH_PREFIX_MORE(prefix, path) {
Set *x; Set *x;
x = hashmap_get(u->manager->units_requiring_mounts_for, prefix); x = hashmap_get(*manager_map, prefix);
if (!x) { if (!x) {
_cleanup_free_ char *q = NULL; _cleanup_free_ char *q = NULL;
r = hashmap_ensure_allocated(&u->manager->units_requiring_mounts_for, &path_hash_ops); r = hashmap_ensure_allocated(manager_map, &path_hash_ops);
if (r < 0) if (r < 0)
return r; return r;
@@ -5001,7 +5028,7 @@ int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask)
if (!x) if (!x)
return -ENOMEM; return -ENOMEM;
r = hashmap_put(u->manager->units_requiring_mounts_for, q, x); r = hashmap_put(*manager_map, q, x);
if (r < 0) { if (r < 0) {
set_free(x); set_free(x);
return r; return r;
@@ -6615,3 +6642,24 @@ int activation_details_append_pair(ActivationDetails *details, char ***strv) {
} }
DEFINE_TRIVIAL_REF_UNREF_FUNC(ActivationDetails, activation_details, activation_details_free); DEFINE_TRIVIAL_REF_UNREF_FUNC(ActivationDetails, activation_details, activation_details_free);
static const char* const unit_mount_dependency_type_table[_UNIT_MOUNT_DEPENDENCY_TYPE_MAX] = {
[UNIT_MOUNT_WANTS] = "WantsMountsFor",
[UNIT_MOUNT_REQUIRES] = "RequiresMountsFor",
};
DEFINE_STRING_TABLE_LOOKUP(unit_mount_dependency_type, UnitMountDependencyType);
UnitDependency unit_mount_dependency_type_to_dependency_type(UnitMountDependencyType t) {
switch (t) {
case UNIT_MOUNT_WANTS:
return UNIT_WANTS;
case UNIT_MOUNT_REQUIRES:
return UNIT_REQUIRES;
default:
assert_not_reached();
}
}
+17 -4
View File
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once #pragma once
#include <errno.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/socket.h> #include <sys/socket.h>
@@ -8,6 +9,14 @@
#include "sd-id128.h" #include "sd-id128.h"
/* Circular dependency with manager.h, needs to be defined before local includes */
typedef enum UnitMountDependencyType {
UNIT_MOUNT_WANTS,
UNIT_MOUNT_REQUIRES,
_UNIT_MOUNT_DEPENDENCY_TYPE_MAX,
_UNIT_MOUNT_DEPENDENCY_TYPE_INVALID = -EINVAL,
} UnitMountDependencyType;
#include "bpf-program.h" #include "bpf-program.h"
#include "cgroup.h" #include "cgroup.h"
#include "condition.h" #include "condition.h"
@@ -216,9 +225,9 @@ typedef struct Unit {
* Hashmap(UnitDependency → Hashmap(Unit* → UnitDependencyInfo)) */ * Hashmap(UnitDependency → Hashmap(Unit* → UnitDependencyInfo)) */
Hashmap *dependencies; Hashmap *dependencies;
/* Similar, for RequiresMountsFor= path dependencies. The key is the path, the value the /* Similar, for RequiresMountsFor= and WantsMountsFor= path dependencies. The key is the path, the
* UnitDependencyInfo type */ * value the UnitDependencyInfo type */
Hashmap *requires_mounts_for; Hashmap *mounts_for[_UNIT_MOUNT_DEPENDENCY_TYPE_MAX];
char *description; char *description;
char **documentation; char **documentation;
@@ -1001,7 +1010,7 @@ int unit_kill_context(Unit *u, KillContext *c, KillOperation k, PidRef *main_pid
int unit_make_transient(Unit *u); int unit_make_transient(Unit *u);
int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask); int unit_add_mounts_for(Unit *u, const char *path, UnitDependencyMask mask, UnitMountDependencyType type);
bool unit_type_supported(UnitType t); bool unit_type_supported(UnitType t);
@@ -1101,6 +1110,10 @@ int unit_arm_timer(Unit *u, sd_event_source **source, bool relative, usec_t usec
int unit_compare_priority(Unit *a, Unit *b); int unit_compare_priority(Unit *a, Unit *b);
UnitMountDependencyType unit_mount_dependency_type_from_string(const char *s) _const_;
const char* unit_mount_dependency_type_to_string(UnitMountDependencyType t) _const_;
UnitDependency unit_mount_dependency_type_to_dependency_type(UnitMountDependencyType t) _pure_;
/* Macros which append UNIT= or USER_UNIT= to the message */ /* Macros which append UNIT= or USER_UNIT= to the message */
#define log_unit_full_errno_zerook(unit, level, error, ...) \ #define log_unit_full_errno_zerook(unit, level, error, ...) \
+9 -4
View File
@@ -416,15 +416,17 @@ static int write_before(FILE *f, const char *opts) {
"x-systemd.before\0", "Before=%1$s\n"); "x-systemd.before\0", "Before=%1$s\n");
} }
static int write_requires_mounts_for(FILE *f, const char *opts) { static int write_mounts_for(const char *x_opt, const char *unit_setting, FILE *f, const char *opts) {
_cleanup_strv_free_ char **paths = NULL, **paths_escaped = NULL; _cleanup_strv_free_ char **paths = NULL, **paths_escaped = NULL;
_cleanup_free_ char *res = NULL; _cleanup_free_ char *res = NULL;
int r; int r;
assert(x_opt);
assert(unit_setting);
assert(f); assert(f);
assert(opts); assert(opts);
r = fstab_filter_options(opts, "x-systemd.requires-mounts-for\0", NULL, NULL, &paths, NULL); r = fstab_filter_options(opts, x_opt, NULL, NULL, &paths, NULL);
if (r < 0) if (r < 0)
return log_warning_errno(r, "Failed to parse options: %m"); return log_warning_errno(r, "Failed to parse options: %m");
if (r == 0) if (r == 0)
@@ -438,7 +440,7 @@ static int write_requires_mounts_for(FILE *f, const char *opts) {
if (!res) if (!res)
return log_oom(); return log_oom();
fprintf(f, "RequiresMountsFor=%s\n", res); fprintf(f, "%s=%s\n", unit_setting, res);
return 0; return 0;
} }
@@ -458,7 +460,10 @@ static int write_extra_dependencies(FILE *f, const char *opts) {
r = write_before(f, opts); r = write_before(f, opts);
if (r < 0) if (r < 0)
return r; return r;
r = write_requires_mounts_for(f, opts); r = write_mounts_for("x-systemd.requires-mounts-for\0", "RequiresMountsFor", f, opts);
if (r < 0)
return r;
r = write_mounts_for("x-systemd.wants-mounts-for\0", "WantsMountsFor", f, opts);
if (r < 0) if (r < 0)
return r; return r;
} }
+1
View File
@@ -2643,6 +2643,7 @@ static int bus_append_unit_property(sd_bus_message *m, const char *field, const
if (unit_dependency_from_string(field) >= 0 || if (unit_dependency_from_string(field) >= 0 ||
STR_IN_SET(field, "Documentation", STR_IN_SET(field, "Documentation",
"RequiresMountsFor", "RequiresMountsFor",
"WantsMountsFor",
"Markers")) "Markers"))
return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE); return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
@@ -276,6 +276,7 @@ User=
WakeSystem= WakeSystem=
WantedBy= WantedBy=
Wants= Wants=
WantsMountsFor=
WatchdogSec= WatchdogSec=
What= What=
Where= Where=
+1 -1
View File
@@ -12,4 +12,4 @@ After=sysinit.target sockets.target paths.target slices.target tmp.mount
# require /var and /var/tmp, but only add a Wants= type dependency on /tmp, as # require /var and /var/tmp, but only add a Wants= type dependency on /tmp, as
# we support that unit being masked, and this should not be considered an error. # we support that unit being masked, and this should not be considered an error.
RequiresMountsFor=/var /var/tmp RequiresMountsFor=/var /var/tmp
Wants=tmp.mount WantsMountsFor=/tmp