]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
99-systemd.rules: rework SYSTEMD_READY logic for device mapper
authorMartin Wilck <mwilck@suse.com>
Wed, 6 Mar 2024 10:39:00 +0000 (11:39 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Wed, 3 Apr 2024 11:48:14 +0000 (12:48 +0100)
Device mapper devices are set up in multiple steps. The first step, which
generates the initial "add" event, only creates an empty container, which is
useless for higher layers. SYSTEMD_READY should be set to 0 on this event to
avoid premature device activation.

The event that matters is the "activation" event: the first "change" event on
which DM_UDEV_DISABLE_OTHER_RULES_FLAG=1 is not set. When this event arrives,
the device is ready for being scanned by blkid and similar tools, and for being
activated by systemd.

Intermittent events with DM_UDEV_DISABLE_OTHER_RULES_FLAG=1 should be ignored
as far as systemd or higher-level block layers are concerned. Previous device
properties and symlinks should be preserved: the device shouldn't be scanned or
activated, but shouldn't be deactivated, either.  In particular, SYSTEM_READY
shouldn't be set to 0 if it wasn't set before, because that might cause mounted
file systems to be unmounted. Such intermittent events may occur any time,
before or after the "activation" event.

DM_UDEV_DISABLE_OTHER_RULES_FLAG=1 can have multiple reasons. One possible reason
is that the device is suspended. There are other reasons that depend on the
device-mapper subsystem (LVM, multipath, dm-crypt, etc.).

The current systemd rule set

1) sets SYSTEMD_READY=0 if DM_UDEV_DISABLE_OTHER_RULES_FLAG is set in "add"
events;
2) imports SYSTEMD_READY from the udev db if DM_SUSPENDED is set, and jumps to systemd_end;
3) sets SYSTEMD_READY=1, otherwise.

This logic has several flaws:

* 1) can cause file systems to be unmounted if an coldplug event arrives while
a file system is suspended. This rule shouldn't be applied for coldplug events
or in general, "synthetic" add events;
* 2) evaluates DM_SUSPENDED=1, which is a device-mapper internal property.
It's wrong to infer that a device is accessible if DM_SUSPENDED=0.
The jump to systemd_end may cause properties and/or symlinks to be lost;
* 3) is superfluous, because SYSTEMD_READY=1 is equivalent with SYSTEMD_READY
being unset, and can create the wrong impression that the device was explicitly
activated.

This patch fixes the logic as follows:

- apply 1) only if DM_NAME is empty, which is only the case for the first
"genuine add" event;
- change 2) to use DM_UDEV_DISABLE_OTHER_RULES_FLAG instead of DM_SUSPENDED,
and remove the GOTO directive;
- remove 3).

Fixes: b7cf1b6 ("udev: use SYSTEMD_READY to mask uninitialized DM devices")
Fixes: 35a6750 ("rules: set SYSTEMD_READY=0 on DM_UDEV_DISABLE_OTHER_RULES_FLAG=1 only with ADD event (#2747)")
Signed-off-by: Martin Wilck <mwilck@suse.com>
rules.d/99-systemd.rules.in

index df52415a8f24753997ace2bf24f3d410e5251c73..ad0c7e2fb5e45fd4af7c39d5ce85edb8a6dc6c06 100644 (file)
@@ -18,19 +18,18 @@ SUBSYSTEM=="ubi", TAG+="systemd"
 
 SUBSYSTEM=="block", TAG+="systemd"
 
-# We can't make any conclusions about suspended DM devices so let's just import previous SYSTEMD_READY state and skip other rules
-SUBSYSTEM=="block", ENV{DM_SUSPENDED}=="1", IMPORT{db}="SYSTEMD_READY"
-SUBSYSTEM=="block", ENV{DM_SUSPENDED}=="1", GOTO="systemd_end"
+# When a dm device is first created, it's just an empty container. Ignore it.
+# DM_NAME is not set in this case, but it's set on spurious "add" events that occur later.
+SUBSYSTEM=="block", ACTION=="add", KERNEL=="dm-*", ENV{DM_NAME}!="?*", ENV{SYSTEMD_READY}="0"
 
-SUBSYSTEM=="block", ACTION=="add", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0"
+# DM_UDEV_DISABLE_OTHER_RULES_FLAG==1 means that the device shouldn't be probed.
+# Import previous SYSTEMD_READY state.
+SUBSYSTEM=="block", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}=="", IMPORT{db}="SYSTEMD_READY"
 
 # Ignore encrypted devices with no identified superblock on it, since
 # we are probably still calling mke2fs or mkswap on it.
 SUBSYSTEM=="block", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0"
 
-# Explicitly set SYSTEMD_READY=1 for DM devices that don't have it set yet, so that we always have something to import above
-SUBSYSTEM=="block", ENV{DM_UUID}=="?*", ENV{SYSTEMD_READY}=="", ENV{SYSTEMD_READY}="1"
-
 # add symlink to GPT root disk
 SUBSYSTEM=="block", ENV{ID_PART_GPT_AUTO_ROOT}=="1", ENV{ID_FS_TYPE}!="crypto_LUKS", SYMLINK+="gpt-auto-root"
 SUBSYSTEM=="block", ENV{ID_PART_GPT_AUTO_ROOT}=="1", ENV{ID_FS_TYPE}=="crypto_LUKS", SYMLINK+="gpt-auto-root-luks"