diff mbox

[7/7] fix udev rules for failed multipath devices

Message ID 1486790932-30917-8-git-send-email-bmarzins@redhat.com (mailing list archive)
State Superseded, archived
Delegated to: christophe varoqui
Headers show

Commit Message

Benjamin Marzinski Feb. 11, 2017, 5:28 a.m. UTC
11-dm-mpath.rules was only correctly dealing with the case where the
multipath device was unusable because the last path had failed.  If
instead, the last working path was removed from the device on a table
reload, it was not correctly marking the device as unusable. One problem
with fixing this is that when the device table is reloaded,
device-mapper doesn't know if the path devices are usable or not.  To
deal with this, multipath now flags reloads with no usable paths with
DM_SUBSYSTEM_UDEV_FLAG2.

11-dm-mpath.rules now checks for both PATH_FAILED events and reloads
with no valid paths. and disables the other rules.

Cc: Peter Rajnoha <prajnoha@redhat.com>
Cc: Hannes Reinecke <hare@suse.de>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/devmapper.c    |  3 +-
 libmultipath/devmapper.h    |  6 ++++
 multipath/11-dm-mpath.rules | 69 +++++++++++++++++++++++++++++++--------------
 3 files changed, 56 insertions(+), 22 deletions(-)

Comments

Peter Rajnoha Feb. 13, 2017, 3:46 p.m. UTC | #1
On 02/11/2017 06:28 AM, Benjamin Marzinski wrote:
> diff --git a/multipath/11-dm-mpath.rules b/multipath/11-dm-mpath.rules
> index 5559af3..b253433 100644
> --- a/multipath/11-dm-mpath.rules
> +++ b/multipath/11-dm-mpath.rules
> @@ -2,39 +2,66 @@ 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"
> +
> +# If this uevent didn't come from dm, don't try to update the
> +# device state
> +ENV{DM_ACTIVATION}!="1", DM_ACTION!="?*", IMPORT{db}="DM_UDEV_DISABLE_OTHER_RULES_FLAG", IMPORT{db}="DM_NOSCAN", GOTO="scan_import"
> +

...

> +# This event is either a PATH_REINSTATED or a table reload where
> +# there are active paths. Mark the device ready
> +ENV{MPATH_DEVICE_READY}=""
> +

If we're doing coldplug (the "udevadm trigger --action=add" or "echo add
> /sys/block/<devname>/uevent"), I think this will drop any existing
MPATH_DEVICE_READY="0" here. Thing is that the ENV{DM_ACTIVATION}="1" is
also set for the coldplug case which generates spurious events, not only
for uevents coming from DM directly.

What we can do though is that we can check for DM_COOKIE and
DM_ACTION="PATH_*" variable existence in which case the uevent surely
comes from DM/mpath driver directly from kernel, so we can rule out the
coldplug case with spurious events.
Benjamin Marzinski Feb. 13, 2017, 5:49 p.m. UTC | #2
On Mon, Feb 13, 2017 at 04:46:07PM +0100, Peter Rajnoha wrote:
> On 02/11/2017 06:28 AM, Benjamin Marzinski wrote:
> > diff --git a/multipath/11-dm-mpath.rules b/multipath/11-dm-mpath.rules
> > index 5559af3..b253433 100644
> > --- a/multipath/11-dm-mpath.rules
> > +++ b/multipath/11-dm-mpath.rules
> > @@ -2,39 +2,66 @@ 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"
> > +
> > +# If this uevent didn't come from dm, don't try to update the
> > +# device state
> > +ENV{DM_ACTIVATION}!="1", DM_ACTION!="?*", IMPORT{db}="DM_UDEV_DISABLE_OTHER_RULES_FLAG", IMPORT{db}="DM_NOSCAN", GOTO="scan_import"
> > +
> 
> ...
> 
> > +# This event is either a PATH_REINSTATED or a table reload where
> > +# there are active paths. Mark the device ready
> > +ENV{MPATH_DEVICE_READY}=""
> > +
> 
> If we're doing coldplug (the "udevadm trigger --action=add" or "echo add
> > /sys/block/<devname>/uevent"), I think this will drop any existing
> MPATH_DEVICE_READY="0" here. Thing is that the ENV{DM_ACTIVATION}="1" is
> also set for the coldplug case which generates spurious events, not only
> for uevents coming from DM directly.
> 
> What we can do though is that we can check for DM_COOKIE and
> DM_ACTION="PATH_*" variable existence in which case the uevent surely
> comes from DM/mpath driver directly from kernel, so we can rule out the
> coldplug case with spurious events.

You're right. I'll change this.

Thanks.
-Ben

> 
> -- 
> Peter

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
diff mbox

Patch

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 4f8ef13..1b43c44 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -373,7 +373,8 @@  int dm_addmap_reload(struct multipath *mpp, char *params, int flush)
 	int r;
 	uint16_t udev_flags = (flush ? 0 : MPATH_UDEV_RELOAD_FLAG) |
 			      ((mpp->skip_kpartx == SKIP_KPARTX_ON)?
-			       MPATH_UDEV_NO_KPARTX_FLAG : 0);
+			       MPATH_UDEV_NO_KPARTX_FLAG : 0) |
+			      ((mpp->nr_active)? 0 : MPATH_UDEV_NO_PATHS_FLAG);
 
 	/*
 	 * DM_DEVICE_RELOAD cannot wait on a cookie, as
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index 411177d..3ea4329 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -18,6 +18,12 @@ 
 #define MPATH_UDEV_NO_KPARTX_FLAG 0
 #endif
 
+#ifdef DM_SUBSYSTEM_UDEV_FLAG2
+#define MPATH_UDEV_NO_PATHS_FLAG DM_SUBSYSTEM_UDEV_FLAG2
+#else
+#define MPATH_UDEV_NO_PATHS_FLAG 0
+#endif
+
 void dm_init(int verbosity);
 int dm_prereq (void);
 int dm_drv_version (unsigned int * version, char * str);
diff --git a/multipath/11-dm-mpath.rules b/multipath/11-dm-mpath.rules
index 5559af3..b253433 100644
--- a/multipath/11-dm-mpath.rules
+++ b/multipath/11-dm-mpath.rules
@@ -2,39 +2,66 @@  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"
+
+# If this uevent didn't come from dm, don't try to update the
+# device state
+ENV{DM_ACTIVATION}!="1", DM_ACTION!="?*", IMPORT{db}="DM_UDEV_DISABLE_OTHER_RULES_FLAG", IMPORT{db}="DM_NOSCAN", GOTO="scan_import"
+
+ENV{.MPATH_DEVICE_READY_OLD}="$env{MPATH_DEVICE_READY}"
+
+# multipath sets DM_SUBSYSTEM_UDEV_FLAG2 when it reloads a
+# table with no active devices. If this happens, mark the
+# device not ready
+ENV{DM_SUBSYSTEM_UDEV_FLAG2}=="1", ENV{MPATH_DEVICE_READY}="0",\
+	GOTO="mpath_action"
+
+# If the last path has failed mark the device not ready
+ENV{DM_ACTION}=="PATH_FAILED", ENV{DM_NR_VALID_PATHS}=="0",\
+	ENV{MPATH_DEVICE_READY}="0", GOTO="mpath_action"
+
+# Don't mark a device ready on a PATH_FAILED event. even if
+# DM_NR_VALID_PATHS is greater than 0. Just keep the existing
+# value
+ENV{DM_ACTION}=="PATH_FAILED", GOTO="mpath_action"
+
+# This event is either a PATH_REINSTATED or a table reload where
+# there are active paths. Mark the device ready
+ENV{MPATH_DEVICE_READY}=""
+
+LABEL="mpath_action"
+# DM_SUBSYSTEM_UDEV_FLAG0 is the "RELOAD" flag for multipath subsystem.
+# Drop the DM_ACTIVATION flag here as mpath reloads tables if any of its
+# paths are lost/recovered. For any stack above the mpath device, this is not
+# something that should be reacted upon since it would be useless extra work.
+# It's exactly mpath's job to provide *seamless* device access to any of the
+# paths that are available underneath.
+ENV{DM_SUBSYSTEM_UDEV_FLAG0}=="1", ENV{DM_ACTIVATION}="0"
+
 # Do not initiate scanning if no path is available,
 # otherwise there would be a hang or IO error on access.
 # We'd like to avoid this, especially within udev processing.
-ENV{DM_NR_VALID_PATHS}!="?*", IMPORT{db}="DM_NR_VALID_PATHS"
-ENV{DM_NR_VALID_PATHS}!="0", GOTO="mpath_blkid_end"
-ENV{ID_FS_TYPE}!="?*", IMPORT{db}="ID_FS_TYPE"
-ENV{ID_FS_USAGE}!="?*", IMPORT{db}="ID_FS_USAGE"
-ENV{ID_FS_UUID}!="?*", IMPORT{db}="ID_FS_UUID"
-ENV{ID_FS_ENC}!="?*", IMPORT{db}="ID_FS_UUID_ENC"
-ENV{ID_FS_VERSION}!="?*", IMPORT{db}="ID_FS_VERSION"
-LABEL="mpath_blkid_end"
+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.
-IMPORT{db}="DM_DISABLE_OTHER_RULES_FLAG_OLD"
-ENV{DM_ACTION}=="PATH_FAILED",\
-	ENV{DM_NR_VALID_PATHS}=="0",\
+i# and restore it back once we have at least one path available.
+ENV{MPATH_DEVICE_READY}=="0", ENV{.MPATH_DEVICE_READY_OLD}!="0",\
 	ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}=="",\
 	ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}="$env{DM_UDEV_DISABLE_OTHER_RULES_FLAG}",\
 	ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1"
-ENV{DM_ACTION}=="PATH_REINSTATED",\
-	ENV{DM_NR_VALID_PATHS}=="1",\
+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"
 
-# DM_SUBSYSTEM_UDEV_FLAG0 is the "RELOAD" flag for multipath subsystem.
-# Drop the DM_ACTIVATION flag here as mpath reloads tables if any of its
-# paths are lost/recovered. For any stack above the mpath device, this is not
-# something that should be reacted upon since it would be useless extra work.
-# It's exactly mpath's job to provide *seamless* device access to any of the
-# paths that are available underneath.
-ENV{DM_SUBSYSTEM_UDEV_FLAG0}=="1", ENV{DM_ACTIVATION}="0"
+LABEL="scan_import"
+ENV{DM_NOSCAN}!="1", GOTO="mpath_end"
+ENV{ID_FS_TYPE}!="?*", IMPORT{db}="ID_FS_TYPE"
+ENV{ID_FS_USAGE}!="?*", IMPORT{db}="ID_FS_USAGE"
+ENV{ID_FS_UUID}!="?*", IMPORT{db}="ID_FS_UUID"
+ENV{ID_FS_ENC}!="?*", IMPORT{db}="ID_FS_UUID_ENC"
+ENV{ID_FS_VERSION}!="?*", IMPORT{db}="ID_FS_VERSION"
 
 LABEL="mpath_end"