core/mount: allow disabling stop propagation from backing device

With file systems that have volume management functionalities or
volume managers like LVM, it's fine for the backing device of a mount
to disappear after mounted. Currently, we enforce BindsTo= or
StopPropagatedFrom= on the backing device, thus prohibiting such
cases. Instead, let's make this configurable through x-systemd.device-bound.

Closes #16801
Closes #29543
This commit is contained in:
Mike Yuan 2023-10-12 18:38:15 +08:00 committed by Luca Boccassi
parent dced8fe402
commit 707ecf1423
2 changed files with 31 additions and 14 deletions

View file

@ -269,16 +269,15 @@
</varlistentry>
<varlistentry>
<term><option>x-systemd.device-bound</option></term>
<term><option>x-systemd.device-bound=</option></term>
<listitem><para>The block device backed file system will be upgraded
to <varname>BindsTo=</varname> dependency. This option is only useful
when mounting file systems manually with
<citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
as the default dependency in this case is <varname>Requires=</varname>.
This option is already implied by entries in <filename>/etc/fstab</filename>
or by mount units.
</para>
<listitem><para>Takes a boolean argument. If true or no argument, a <varname>BindsTo=</varname> dependency
on the backing device is set. If false, the mount unit is not stopped no matter whether the backing device
is still present. This is useful when the file system is backed by volume managers. If not set, and the mount
comes from unit fragments, i.e. generated from <filename>/etc/fstab</filename> by <citerefentry>
<refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry> or loaded from
a manually configured mount unit, a combination of <varname>Requires=</varname> and <varname>StopPropagatedFrom=</varname>
dependencies is set on the backing device. If doesn't, only <varname>Requires=</varname> is used.</para>
<xi:include href="version-info.xml" xpointer="v233"/></listitem>
</varlistentry>

View file

@ -125,13 +125,15 @@ static bool mount_is_bind(const MountParameters *p) {
return fstab_is_bind(p->options, p->fstype);
}
static bool mount_is_bound_to_device(Mount *m) {
static int mount_is_bound_to_device(Mount *m) {
_cleanup_free_ char *value = NULL;
const MountParameters *p;
int r;
assert(m);
/* Determines whether to place a Requires= or BindsTo= dependency on the backing device unit. We do
* this by checking for the x-systemd.device-bound mount option. Iff it is set we use BindsTo=,
* this by checking for the x-systemd.device-bound= mount option. If it is enabled we use BindsTo=,
* otherwise Requires=. But note that we might combine the latter with StopPropagatedFrom=, see
* below. */
@ -139,14 +141,30 @@ static bool mount_is_bound_to_device(Mount *m) {
if (!p)
return false;
return fstab_test_option(p->options, "x-systemd.device-bound\0");
r = fstab_filter_options(p->options, "x-systemd.device-bound\0", NULL, &value, NULL, NULL);
if (r < 0)
return r;
if (r == 0)
return -EIDRM; /* If unspecified at all, return recognizable error */
if (isempty(value))
return true;
return parse_boolean(value);
}
static bool mount_propagate_stop(Mount *m) {
int r;
assert(m);
if (mount_is_bound_to_device(m)) /* If we are using BindsTo= the stop propagation is implicit, no need to bother */
r = mount_is_bound_to_device(m);
if (r >= 0)
/* If x-systemd.device-bound=no is explicitly requested by user, don't try to set StopPropagatedFrom=.
* Also don't bother if true, since with BindsTo= the stop propagation is implicit. */
return false;
if (r != -EIDRM)
log_debug_errno(r, "Failed to get x-systemd.device-bound= option, ignoring: %m");
return m->from_fragment; /* let's propagate stop whenever this is an explicitly configured unit,
* otherwise let's not bother. */
@ -367,7 +385,7 @@ static int mount_add_device_dependencies(Mount *m) {
* maintain. The user can still force this to be a BindsTo= dependency with an appropriate option (or
* udev property) so the mount units are automatically stopped when the device disappears
* suddenly. */
dep = mount_is_bound_to_device(m) ? UNIT_BINDS_TO : UNIT_REQUIRES;
dep = mount_is_bound_to_device(m) > 0 ? UNIT_BINDS_TO : UNIT_REQUIRES;
/* We always use 'what' from /proc/self/mountinfo if mounted */
mask = m->from_proc_self_mountinfo ? UNIT_DEPENDENCY_MOUNTINFO : UNIT_DEPENDENCY_MOUNT_FILE;