The current rules overwrite DM_UDEV_DISABLE_OTHER_RULES_FLAG and save its value in DM_UDEV_DISABLE_OTHER_RULES_FLAG_OLD if MPATH_DEVICE_READY changes from 1 to 0, and restore DM_UDEV_DISABLE_OTHER_RULES_FLAG from DM_UDEV_DISABLE_OTHER_RULES_FLAG_OLD when MPATH_DEVICE_READY changes back from 0 to 1. This is wrong for multiple reasons. For "spurious" events, 10-dm.rules will read DM_UDEV_DISABLE_OTHER_RULES_FLAG from the udev db and obtain the value saved by 11-dm-mpath.rules rather than it's own saved value, which confuses the logic in 10-dm.rules. 10-dm.rules sets the flag if either DISK_RO==1 or DM_SUSPENDED==1, and never clears it (it can only be cleared by a new genuine libdm event that doesn't have DM_UDEV_DISABLE_OTHER_RULES_FLAG set, while the device is not suspended). lvm commands may set the flag, too, but AFAICS this is only done for certain types of logical volumes, not for multipath maps. If a previously suspended device is resumed, DM_UDEV_DISABLE_OTHER_RULES_FLAG would be cleared, and it would be wrong for 11-dm-mpath.rules to overwrite it with a previuosly saved value. Likewise, if a uevent arrives for a suspended map, and MPATH_DEVICE_READY happens to switch from 0 to 1, it would be wrong to clear DM_UDEV_DISABLE_OTHER_RULES_FLAG by setting it to a previously saved value. We need to set DM_UDEV_DISABLE_OTHER_RULES_FLAG=1 to prevent follow-up rules from attempting I/O on the device. But don't try to save and restore DM_UDEV_DISABLE_OTHER_RULES_FLAG between uevents. Rather, reset DM_UDEV_DISABLE_OTHER_RULES_FLAG to the value we got from 10-dm.rules in a late rule. I chose "z0" for this rule's prefix to make sure it needs to run very late (after 99-systemd.rules, for example) while still allowing some reasonable space after it. Signed-off-by: Martin Wilck <mwilck@xxxxxxxx> --- multipath/11-dm-mpath.rules.in | 19 +++++++++---------- multipath/Makefile | 2 ++ multipath/z0-dm-mpath-late.rules | 4 ++++ 3 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 multipath/z0-dm-mpath-late.rules diff --git a/multipath/11-dm-mpath.rules.in b/multipath/11-dm-mpath.rules.in index 54d01a6..e31107b 100644 --- a/multipath/11-dm-mpath.rules.in +++ b/multipath/11-dm-mpath.rules.in @@ -2,7 +2,6 @@ ACTION!="add|change", GOTO="mpath_end" ENV{DM_UDEV_RULES_VSN}!="?*", GOTO="mpath_end" ENV{DM_UUID}!="mpath-?*", GOTO="mpath_end" -IMPORT{db}="DM_DISABLE_OTHER_RULES_FLAG_OLD" IMPORT{db}="MPATH_DEVICE_READY" # Coldplug event while device is suspended (e.g. during a reload) @@ -79,16 +78,16 @@ LABEL="force_activation" # We'd like to avoid this, especially within udev processing. ENV{MPATH_DEVICE_READY}=="0", ENV{DM_NOSCAN}="1" -# Also skip all foreign rules if no path is available. -# Remember the original value of DM_DISABLE_OTHER_RULES_FLAG -# and restore it back once we have at least one path available. -ENV{MPATH_DEVICE_READY}=="0", ENV{.MPATH_DEVICE_READY_OLD}=="1", \ - ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}=="", \ - ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}="$env{DM_UDEV_DISABLE_OTHER_RULES_FLAG}" -ENV{MPATH_DEVICE_READY}=="0", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1" +# Skip all foreign rules if no path is available. +# Use DM_UDEV_DISABLE_OTHER_RULES_FLAG to communicate this +# to upper layers. The original value will be restored in a late +# udev rule. +ENV{MPATH_DEVICE_READY}=="0", \ + ENV{.MPATH_SAVE_DISABLE_OTHER_RULES_FLAG}="$env{DM_UDEV_DISABLE_OTHER_RULES_FLAG}", \ + ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1" +# If the device comes back online, set DM_ACTIVATION so that +# upper layers do a rescan. ENV{MPATH_DEVICE_READY}!="0", ENV{.MPATH_DEVICE_READY_OLD}=="0", \ - ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="$env{DM_DISABLE_OTHER_RULES_FLAG_OLD}", \ - ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}="", \ ENV{DM_ACTIVATION}="1", ENV{MPATH_UNCHANGED}="0" # The code to check multipath state ends here. We need to set diff --git a/multipath/Makefile b/multipath/Makefile index f8c1f5e..2f2569c 100644 --- a/multipath/Makefile +++ b/multipath/Makefile @@ -26,6 +26,7 @@ install: $(Q)$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/ $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(udevrulesdir) $(Q)$(INSTALL_PROGRAM) -m 644 11-dm-mpath.rules $(DESTDIR)$(udevrulesdir) + $(Q)$(INSTALL_PROGRAM) -m 644 z0-dm-mpath-late.rules $(DESTDIR)$(udevrulesdir) $(Q)$(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)$(udevrulesdir)/56-multipath.rules $(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(tmpfilesdir) $(Q)$(INSTALL_PROGRAM) -m 644 tmpfiles.conf $(DESTDIR)$(tmpfilesdir)/multipath.conf @@ -46,6 +47,7 @@ endif uninstall: $(Q)$(RM) $(DESTDIR)$(bindir)/$(EXEC) $(Q)$(RM) $(DESTDIR)$(udevrulesdir)/11-dm-mpath.rules + $(Q)$(RM) $(DESTDIR)$(udevrulesdir)/z0-dm-mpath-late.rules $(Q)$(RM) $(DESTDIR)$(modulesloaddir)/multipath.conf $(Q)$(RM) $(DESTDIR)$(modulesloaddir)/scsi_dh.conf $(Q)$(RM) $(DESTDIR)$(libudevdir)/rules.d/56-multipath.rules diff --git a/multipath/z0-dm-mpath-late.rules b/multipath/z0-dm-mpath-late.rules new file mode 100644 index 0000000..8574b1a --- /dev/null +++ b/multipath/z0-dm-mpath-late.rules @@ -0,0 +1,4 @@ +# If DM_UDEV_DISABLE_OTHER_RULES_FLAG was modified in 11-dm-mpath.rules, +# restore it here, lest a temporary value be saved in the udev db +ACTION=="add|change", ENV{.MPATH_SAVE_DISABLE_OTHER_RULES_FLAG}=="?*", \ + ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="$env{.MPATH_SAVE_DISABLE_OTHER_RULES_FLAG}" -- 2.43.0