Linux Device Mapper development
 help / color / mirror / Atom feed
* [PATCH 0/3] New approach at handling changed WWIDs
@ 2019-03-18 12:12 Martin Wilck
  2019-03-18 12:12 ` [PATCH 1/3] multipathd: handle changed wwids by removal and addition Martin Wilck
                   ` (3 more replies)
  0 siblings, 4 replies; 12+ messages in thread
From: Martin Wilck @ 2019-03-18 12:12 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel, Martin Wilck

Hi Ben, hi Christophe,

after reviewing Ben's last patch set, I've been pondering over the
handling of changed WWIDs, which seems to have become a bit too clever
and complex for my taste, and I came up with this new approach
instead.

TL;DR: instead of treating paths with changed WWIDs as faulty, act
as if the path was removed, and another path was then added and
obtained the device ID of the removed path.

Long version:

What would cause the WWID of an in-use path to change on the fly? Other than
a) gross malfunction of the storage or kernel (which would be almost certain
to corrupt data anyway, whether or not multipathd is taking precautions),
I can think of two scenarios: b) multipathd might have missed both a
"remove" and a subsequent "add" uevent for the device in question; c)
the admin may have played with the udev rules, and solicited change
uevents manually.

In case b), doing what my patch does is obviously the right thing. In case
c), the right thing would be throwing slimy stinking things at the admin,
but as we can't do that, removing and re-adding seems still more reasonable
than pretending the path was faulty. Even in case a), removing the path
from the current map is no worse than failing it.

What remains to be considered is what Ben was dealing with in his latest set,
a permanent or temporary failure to retrieve the WWID, resulting in a 0-length
WWID to be returned. IMO it's actually the best thing about this new approach
that this doesn't need to be special-cased. The path initialization logic
that we already have would take care of it using the INIT_MISSING_UDEV logic.
Either the WWID would be successfully retrieved eventually, in which case the
path would be re-added to the previous map, or (depending on configuration)
added to a new map or left alone. Or the failure is permanent, in which case
multipathd would eventually give up and orphan the path. AFAICS this would
be the "right thing" to do in all these different cases, without any
additional logic.

Note also that if a "reconfigure" was carried out in the presence of
paths with changed WWID, the final outcome would likely be the same that
my patch now achieves without "reconfigure".

I case I've come to the wrong conclusions because I overlooked something
essential, please tell me.

Going one step futher, I've actually come to think differently about the
"fallback logic" for the case that no WWID can be obtained from udev. I
believe now that such fallback logic should _not_ be used. The point is not
to derive _some_ WWID, but _the right one_, and that's udev's job. But udev
can be customized in complex ways that multipathd has no idea about.
In the worst case, we'd receive some WWIDs from udev and some from our
own logic, and combine paths into a map which wouldn't acutally belong
together. Therefore I vote for ripping out the fallback logic altogether
and depend on udev exclusively for WWID generation. I haven't included this
in the current patch set in order not to make it too controversial.

The only purpose for the fallback logic that I could see is to provide
a configuration option to force multipathd to _always_ determine the
WWID by itself, ignoring udev device properties.

Regards
Martin

Martin Wilck (3):
  multipathd: handle changed wwids by removal and addition
  multipathd: remove "wwid_changed" path attribute
  multipathd: ignore "disable_changed_wwids"

 libmultipath/config.c      |  1 -
 libmultipath/config.h      |  1 -
 libmultipath/dict.c        | 18 +++++++--
 libmultipath/structs.h     |  1 -
 multipath/multipath.conf.5 |  8 +---
 multipathd/main.c          | 77 +++++++++++++++++++-------------------
 6 files changed, 55 insertions(+), 51 deletions(-)

-- 
2.21.0

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/3] multipathd: handle changed wwids by removal and addition
  2019-03-18 12:12 [PATCH 0/3] New approach at handling changed WWIDs Martin Wilck
@ 2019-03-18 12:12 ` Martin Wilck
  2019-03-18 12:12 ` [PATCH 2/3] multipathd: remove "wwid_changed" path attribute Martin Wilck
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 12+ messages in thread
From: Martin Wilck @ 2019-03-18 12:12 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel, Martin Wilck

If a path's WWID changes, it's not necessarily failed. But it certainly
has to be removed from an existing map, otherwise data corruption is
imminent. Instead of keeping the path in the map, failing it, and
remembering the "changed WWID" state, this patch simply removes and
re-adds the path.

If the WWID is truly different now, the path will be readded as if
it was a new path. If the WWID is zero because of a (possibly temporary)
getuid() failure, and getuid() fails in uev_add_path() again, it
will be added with INIT_MISSING_UDEV status and thus handled appropriately
by the "missing udev" logic.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 multipathd/main.c | 71 +++++++++++++++++++++++++----------------------
 1 file changed, 38 insertions(+), 33 deletions(-)

diff --git a/multipathd/main.c b/multipathd/main.c
index fb520b64..bd26209d 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -1184,13 +1184,22 @@ fail:
 	return 1;
 }
 
+static bool is_wwid_changed(const struct path *pp, const char *old_wwid)
+{
+	bool wwid_changed = (strncmp(old_wwid, pp->wwid, WWID_SIZE) != 0);
+
+	if (wwid_changed)
+		condlog(1, "%s: WWID changed from \"%s\" to \"%s\"",
+			pp->dev, old_wwid, pp->wwid);
+	return wwid_changed;
+}
+
 static int
 uev_update_path (struct uevent *uev, struct vectors * vecs)
 {
 	int ro, retval = 0, rc;
 	struct path * pp;
 	struct config *conf;
-	int disable_changed_wwids;
 	int needs_reinit = 0;
 
 	switch ((rc = change_foreign(uev->udev))) {
@@ -1208,12 +1217,6 @@ uev_update_path (struct uevent *uev, struct vectors * vecs)
 		break;
 	}
 
-	conf = get_multipath_config();
-	disable_changed_wwids = conf->disable_changed_wwids;
-	put_multipath_config(conf);
-
-	ro = uevent_get_disk_ro(uev);
-
 	pthread_cleanup_push(cleanup_lock, &vecs->lock);
 	lock(&vecs->lock);
 	pthread_testcancel();
@@ -1221,7 +1224,7 @@ uev_update_path (struct uevent *uev, struct vectors * vecs)
 	pp = find_path_by_dev(vecs->pathvec, uev->kernel);
 	if (pp) {
 		struct multipath *mpp = pp->mpp;
-		char wwid[WWID_SIZE];
+		bool wwid_changed;
 
 		if (pp->initialized == INIT_REQUESTED_UDEV) {
 			needs_reinit = 1;
@@ -1232,36 +1235,38 @@ uev_update_path (struct uevent *uev, struct vectors * vecs)
 		if (!strlen(pp->wwid))
 			goto out;
 
-		strcpy(wwid, pp->wwid);
-		get_uid(pp, pp->state, uev->udev);
-
-		if (strncmp(wwid, pp->wwid, WWID_SIZE) != 0) {
-			condlog(0, "%s: path wwid changed from '%s' to '%s'. %s",
-				uev->kernel, wwid, pp->wwid,
-				(disable_changed_wwids ? "disallowing" :
-				 "continuing"));
-			strcpy(pp->wwid, wwid);
-			if (disable_changed_wwids) {
-				if (!pp->wwid_changed) {
-					pp->wwid_changed = 1;
-					pp->tick = 1;
-					if (pp->mpp)
-						dm_fail_path(pp->mpp->alias, pp->dev_t);
-				}
-				goto out;
-			}
+		if (pp->mpp) {
+			get_uid(pp, pp->state, uev->udev);
+			wwid_changed = is_wwid_changed(pp, pp->mpp->wwid);
 		} else {
-			pp->wwid_changed = 0;
+			char *old_wwid = strdup(pp->wwid);
+
+			if (!old_wwid)
+				goto out;
+			pthread_cleanup_push(free, (void*)old_wwid);
+			wwid_changed = is_wwid_changed(pp, old_wwid);
+			pthread_cleanup_pop(1);
+		}
+
+		if (wwid_changed) {
+			ev_remove_path(pp, vecs, 1);
+			needs_reinit = 1;
+			goto out;
+		}
+
+		if (pp->udev != uev->udev) {
 			udev_device_unref(pp->udev);
 			pp->udev = udev_device_ref(uev->udev);
-			conf = get_multipath_config();
-			pthread_cleanup_push(put_multipath_config, conf);
-			if (pathinfo(pp, conf, DI_SYSFS|DI_NOIO) != PATHINFO_OK)
-				condlog(1, "%s: pathinfo failed after change uevent",
-					uev->kernel);
-			pthread_cleanup_pop(1);
 		}
 
+		conf = get_multipath_config();
+		pthread_cleanup_push(put_multipath_config, conf);
+		if (pathinfo(pp, conf, DI_SYSFS|DI_NOIO) != PATHINFO_OK)
+			condlog(1, "%s: pathinfo failed after change uevent",
+				uev->kernel);
+		pthread_cleanup_pop(1);
+
+		ro = uevent_get_disk_ro(uev);
 		if (mpp && ro >= 0) {
 			condlog(2, "%s: update path write_protect to '%d' (uevent)", uev->kernel, ro);
 
-- 
2.21.0

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/3] multipathd: remove "wwid_changed" path attribute
  2019-03-18 12:12 [PATCH 0/3] New approach at handling changed WWIDs Martin Wilck
  2019-03-18 12:12 ` [PATCH 1/3] multipathd: handle changed wwids by removal and addition Martin Wilck
@ 2019-03-18 12:12 ` Martin Wilck
  2019-03-18 12:12 ` [PATCH 3/3] multipathd: ignore "disable_changed_wwids" Martin Wilck
  2019-03-19 17:11 ` [PATCH 0/3] New approach at handling changed WWIDs Benjamin Marzinski
  3 siblings, 0 replies; 12+ messages in thread
From: Martin Wilck @ 2019-03-18 12:12 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel, Martin Wilck

This is now not needed any more.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/structs.h | 1 -
 multipathd/main.c      | 6 ------
 2 files changed, 7 deletions(-)

diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index b794b0dc..7879d763 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -280,7 +280,6 @@ struct path {
 	int fd;
 	int initialized;
 	int retriggers;
-	int wwid_changed;
 	unsigned int path_failures;
 	time_t dis_reinstate_time;
 	int disable_reinstate;
diff --git a/multipathd/main.c b/multipathd/main.c
index bd26209d..7119894c 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -2016,12 +2016,6 @@ check_path (struct vectors * vecs, struct path * pp, int ticks)
 	if (newstate == PATH_REMOVED)
 		newstate = PATH_DOWN;
 
-	if (pp->wwid_changed) {
-		condlog(2, "%s: path wwid has changed. Refusing to use",
-			pp->dev);
-		newstate = PATH_DOWN;
-	}
-
 	if (newstate == PATH_WILD || newstate == PATH_UNCHECKED) {
 		condlog(2, "%s: unusable path (%s) - checker failed",
 			pp->dev, checker_state_name(newstate));
-- 
2.21.0

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/3] multipathd: ignore "disable_changed_wwids"
  2019-03-18 12:12 [PATCH 0/3] New approach at handling changed WWIDs Martin Wilck
  2019-03-18 12:12 ` [PATCH 1/3] multipathd: handle changed wwids by removal and addition Martin Wilck
  2019-03-18 12:12 ` [PATCH 2/3] multipathd: remove "wwid_changed" path attribute Martin Wilck
@ 2019-03-18 12:12 ` Martin Wilck
  2019-03-19 17:11 ` [PATCH 0/3] New approach at handling changed WWIDs Benjamin Marzinski
  3 siblings, 0 replies; 12+ messages in thread
From: Martin Wilck @ 2019-03-18 12:12 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel, Martin Wilck

This option has no effect any more.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/config.c      |  1 -
 libmultipath/config.h      |  1 -
 libmultipath/dict.c        | 18 +++++++++++++++---
 multipath/multipath.conf.5 |  8 ++------
 4 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/libmultipath/config.c b/libmultipath/config.c
index 24d71aed..141f092b 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -715,7 +715,6 @@ load_config (char * file)
 	conf->retrigger_tries = DEFAULT_RETRIGGER_TRIES;
 	conf->retrigger_delay = DEFAULT_RETRIGGER_DELAY;
 	conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT;
-	conf->disable_changed_wwids = DEFAULT_DISABLE_CHANGED_WWIDS;
 	conf->remove_retries = 0;
 	conf->ghost_delay = DEFAULT_GHOST_DELAY;
 	conf->all_tg_pt = DEFAULT_ALL_TG_PT;
diff --git a/libmultipath/config.h b/libmultipath/config.h
index b938c26c..f5bf5b1b 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -182,7 +182,6 @@ struct config {
 	int delayed_reconfig;
 	int uev_wait_timeout;
 	int skip_kpartx;
-	int disable_changed_wwids;
 	int remove_retries;
 	int max_sectors_kb;
 	int ghost_delay;
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index eaad4f18..96815f8a 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -156,6 +156,12 @@ out:
 	return len;
 }
 
+static int
+print_ignored (char *buff, int len)
+{
+	return snprintf(buff, len, "ignored");
+}
+
 static int
 print_yes_no (char *buff, int len, long v)
 {
@@ -548,9 +554,15 @@ declare_hw_handler(skip_kpartx, set_yes_no_undef)
 declare_hw_snprint(skip_kpartx, print_yes_no_undef)
 declare_mp_handler(skip_kpartx, set_yes_no_undef)
 declare_mp_snprint(skip_kpartx, print_yes_no_undef)
-
-declare_def_handler(disable_changed_wwids, set_yes_no)
-declare_def_snprint(disable_changed_wwids, print_yes_no)
+static int def_disable_changed_wwids_handler(struct config *conf, vector strvec)
+{
+	return 0;
+}
+static int snprint_def_disable_changed_wwids(struct config *conf, char *buff,
+					     int len, const void *data)
+{
+	return print_ignored(buff, len);
+}
 
 declare_def_handler(remove_retries, set_int)
 declare_def_snprint(remove_retries, print_int)
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index 0fe8461d..a2e3e866 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -1148,12 +1148,8 @@ The default is: \fBno\fR
 .
 .TP
 .B disable_changed_wwids
-If set to \fIyes\fR, multipathd will check the path wwid on change events, and
-if it has changed from the wwid of the multipath device, multipathd will
-disable access to the path until the wwid changes back.
-.RS
-.TP
-The default is: \fBno\fR
+This option is deprecated and ignored. If the WWID of a path suddenly changes,
+multipathd handles it as if it was removed and then added again.
 .RE
 .
 .
-- 
2.21.0

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/3] New approach at handling changed WWIDs
  2019-03-18 12:12 [PATCH 0/3] New approach at handling changed WWIDs Martin Wilck
                   ` (2 preceding siblings ...)
  2019-03-18 12:12 ` [PATCH 3/3] multipathd: ignore "disable_changed_wwids" Martin Wilck
@ 2019-03-19 17:11 ` Benjamin Marzinski
  2019-03-19 18:44   ` Martin Wilck
  3 siblings, 1 reply; 12+ messages in thread
From: Benjamin Marzinski @ 2019-03-19 17:11 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Mon, Mar 18, 2019 at 01:12:32PM +0100, Martin Wilck wrote:
> Hi Ben, hi Christophe,
> 
> after reviewing Ben's last patch set, I've been pondering over the
> handling of changed WWIDs, which seems to have become a bit too clever
> and complex for my taste, and I came up with this new approach
> instead.
> 
> TL;DR: instead of treating paths with changed WWIDs as faulty, act
> as if the path was removed, and another path was then added and
> obtained the device ID of the removed path.
> 
> Long version:

Mine is even longer. Sorry :(

> What would cause the WWID of an in-use path to change on the fly? Other than
> a) gross malfunction of the storage or kernel (which would be almost certain
> to corrupt data anyway, whether or not multipathd is taking precautions),
> I can think of two scenarios: b) multipathd might have missed both a
> "remove" and a subsequent "add" uevent for the device in question; c)
> the admin may have played with the udev rules, and solicited change
> uevents manually.

The issue that orginally caused me to check for a changed wwid was a
user remapping in-use storage on the array, so an existing device no
longer mapped to the same underlying disks. That generally fits under c)
"admin did something stupid". 

I don't believe that b) is something we actually need to worry about.
In that case, multipathd will still have the old fd for the path device,
which will remain unusable, so the path will never get re-enabled.
Also, the kernel should never reuse a device name, if things still have
the old device name open.

So, as far as I know, the only way that the wwid could get legitimately
remapped, barring something like a), which there is no point in trying
to fix, is because of user error (or at least some other program's
error). 

While I agree that a path's wwid changing to a different non-null wwid
is always bad, and removing and re-adding the path seems perfectly
sensible for that scenario, I've can think of two other case where the
wwid can change to null.  d) a change event happens while the path is
down.  e) there is a uevent storm and udev times out while handling a
change event.

d) and e) seem to me like by far the most likely scenarios, so doing
something suboptimal for them, in order to optimize the very unlikely
scenarios seems wrong.

Have you ever seen this happen where it was multipaths fault?  I
have never seen this happen in the real world where I didn't also see
a kernel message like this in the logs:

kernel: sd 10:0:0:0: Warning! Received an indication that the LUN assignments on this target have changed. The Linux SCSI layer does not automatically remap LUN assignments.
 
This is a pretty clear sign that something bad has happened to the
storage. And it as always been that someone or something has
reconfigured in-use storage in a dangerous way.

> In case b), doing what my patch does is obviously the right thing. In case
> c), the right thing would be throwing slimy stinking things at the admin,
> but as we can't do that, removing and re-adding seems still more reasonable
> than pretending the path was faulty. Even in case a), removing the path
> from the current map is no worse than failing it.
> 
> What remains to be considered is what Ben was dealing with in his latest set,
> a permanent or temporary failure to retrieve the WWID, resulting in a 0-length
> WWID to be returned. IMO it's actually the best thing about this new approach
> that this doesn't need to be special-cased. The path initialization logic
> that we already have would take care of it using the INIT_MISSING_UDEV logic.
> Either the WWID would be successfully retrieved eventually, in which case the
> path would be re-added to the previous map, or (depending on configuration)
> added to a new map or left alone. Or the failure is permanent, in which case
> multipathd would eventually give up and orphan the path. AFAICS this would
> be the "right thing" to do in all these different cases, without any
> additional logic.

This is where I don't fully agree. It means that we can be stuck waiting
for a uevent to occur when the device has come back up, instead of just
restoring it.  I would really like to keep as little code as possible
that needs to get run before we restore a working path, because that
could be, for instance, the last path to your root filesystem, and you
can't touch any non-cached files on it, until you restore that path.

Even aside from the extreme case, multipathd is doing a lot of extra
work, and quite possibly adding a lot of confusing log messages, simply
because of an unfortunately timed change event.
 
> Note also that if a "reconfigure" was carried out in the presence of
> paths with changed WWID, the final outcome would likely be the same that
> my patch now achieves without "reconfigure".

Yeah. I just checked, and this is very broken, and something needs to be
done to fix it.  If a device gets a change event while it's down, it
will no longer have the udev properties necessary to not be blacklisted,
so the device gets blacklisted, and ignored.  Even after it comes back
up and gest another change event to restore these values, multipathd
still ignores it, because the device was blacklisted during its add
event.

However, if you just set the wwid of a path to NULL and run reconfigure,
it will stay added to the map, and get it's wwid restored to the
multipath device's wwid, because configure() calls map_discovery(),
which ends up calling disassemble_map(). This will set a NULL path wwid
to the multipath device wwid, since disassemble_map() assumes that NULL
wwids just mean that multipathd couldn't get the wwid temporarily.

> I case I've come to the wrong conclusions because I overlooked something
> essential, please tell me.
> 
> Going one step futher, I've actually come to think differently about the
> "fallback logic" for the case that no WWID can be obtained from udev. I
> believe now that such fallback logic should _not_ be used. The point is not
> to derive _some_ WWID, but _the right one_, and that's udev's job. But udev
> can be customized in complex ways that multipathd has no idea about.
> In the worst case, we'd receive some WWIDs from udev and some from our
> own logic, and combine paths into a map which wouldn't acutally belong
> together. Therefore I vote for ripping out the fallback logic altogether
> and depend on udev exclusively for WWID generation. I haven't included this
> in the current patch set in order not to make it too controversial.
>
> The only purpose for the fallback logic that I could see is to provide
> a configuration option to force multipathd to _always_ determine the
> WWID by itself, ignoring udev device properties.

I understand your concern.  There are currently safeguards (obviously
not foolproof ones). The fallback wwid has to match the existing wwid,
otherwise the path gets disabled. It seems very unlikely that a path
configured to use the default uid_attribute, which switched to the
fallback method and still got the same wwid, should actually have a
different udev wwid than the one it previously had and that the fallback
method still has.  Also, once a path starts using the fallback method,
it clears uid_attribute, so that it keeps using the fallback method.

But to get back to dealing with changed wwids, I agree with removing an
re-adding a device if it's wwid has changed. So, leaving that aside, the
sticky question is "what to do with a path that has a NULL wwid?"

There are a number of options:

1. Ignore the NULL wwid. This is what my patch 07 does, and I'd like to
make the case for this yet again. I feel pretty sure that a NULL wwid on
a change event is almost always going to occur because that change event
happened when the path was down. If that's not the reason, then I
believe it is either your reasons a) or c) from above. a) is not
fixable. c) is not really our problem. It's a service to try saving the
sysadmin from their own mistakes. But there is no way to make it
foolproof. It is always possible for the device to get remapped and
start getting IO before multipathd ever gets the uevent. The best we can
guarantee is that we will eventually detect when this happens, report
it, and stop it from doing more damage.  Given this, I think it's
perfectly reasonable to just let NULL wwids slide, because that's
ususally the right thing to do, and everything else makes the common
case work worse, while still not providing a guarantee that the worst
case is avoided. This is still my preferred solution.

2. Fail the path on a NULL wwid. In the checker loop, when the path is
up again, re-attempt to get the wwid.  However, since the udev
information we have won't contain the new wwid, use the fallback
information. This is my patch 12, and I agree that there could be issues
with the fallback wwid being determined differently, although like I
mentioned above, multipathd tries to deal with them.

3. Fail the path on a NULL wwid. In the checker loop, when the path is
up again, trigger a change uevent to get the new information. This
delays restoring a path once it's up, and increases the number of things
outside of multipathd's control that could go wrong which would keep the
path from getting restored (udev timeouts, inability for udev to
complete, because access to a necessary device is down).

4. Some sort of hybrid of 2 and 3, where devices can either get their
wwid from udev or directly from the device, and depending on how they
get their wwid, by necessity they do different things. This is workable
but a lot of code for something that is just a best-effort attempt to
protect sysadmins from themselves.

4. Completely remove the path, and try to re-add it.  This method will
likely cause at least as much delay as 3, with an even larger chance
that something goes wrong and keeps access from being restored. That's
completely fine if the wwid has changed to something else, but I really
don't like having to do all that work just because a change event
occurred on a device that was down.

Thoughts?

-Ben
 
> Regards
> Martin
> 
> Martin Wilck (3):
>   multipathd: handle changed wwids by removal and addition
>   multipathd: remove "wwid_changed" path attribute
>   multipathd: ignore "disable_changed_wwids"
> 
>  libmultipath/config.c      |  1 -
>  libmultipath/config.h      |  1 -
>  libmultipath/dict.c        | 18 +++++++--
>  libmultipath/structs.h     |  1 -
>  multipath/multipath.conf.5 |  8 +---
>  multipathd/main.c          | 77 +++++++++++++++++++-------------------
>  6 files changed, 55 insertions(+), 51 deletions(-)
> 
> -- 
> 2.21.0

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/3] New approach at handling changed WWIDs
  2019-03-19 17:11 ` [PATCH 0/3] New approach at handling changed WWIDs Benjamin Marzinski
@ 2019-03-19 18:44   ` Martin Wilck
  2019-03-20  8:37     ` Martin Wilck
  2019-03-25 22:27     ` Benjamin Marzinski
  0 siblings, 2 replies; 12+ messages in thread
From: Martin Wilck @ 2019-03-19 18:44 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: dm-devel

On Tue, 2019-03-19 at 12:11 -0500, Benjamin Marzinski wrote:
> On Mon, Mar 18, 2019 at 01:12:32PM +0100, Martin Wilck wrote:
> > Hi Ben, hi Christophe,
> > 
> > after reviewing Ben's last patch set, I've been pondering over the
> > handling of changed WWIDs, which seems to have become a bit too
> > clever
> > and complex for my taste, and I came up with this new approach
> > instead.
> > 
> > TL;DR: instead of treating paths with changed WWIDs as faulty, act
> > as if the path was removed, and another path was then added and
> > obtained the device ID of the removed path.
> > 
> > Long version:
> 
> Mine is even longer. Sorry :(

NP, but you'll forgive me for shortening it a a bit for my reply :-)

> While I agree that a path's wwid changing to a different non-null
> wwid
> is always bad, and removing and re-adding the path seems perfectly
> sensible for that scenario, I've can think of two other case where
> the
> wwid can change to null.  d) a change event happens while the path is
> down.  e) there is a uevent storm and udev times out while handling a
> change event.
> 
> d) and e) seem to me like by far the most likely scenarios, so doing
> something suboptimal for them, in order to optimize the very unlikely
> scenarios seems wrong.

You've worked on this far more than I did, so I trust your judgement.

One remark: With the kernel exporting the VPD pages in sysfs
and my late "multipath -u" patch series, udev should be able to process
uevents for path devices without a single actual device IO. (*) 
While there are still possible causes for udev processing to get stuck,
this would make it much less likely.

> > What remains to be considered is what Ben was dealing with in his
> > latest set,
> > a permanent or temporary failure to retrieve the WWID, resulting in
> > a 0-length
> > WWID to be returned. IMO it's actually the best thing about this
> > new approach
> > that this doesn't need to be special-cased. The path initialization
> > logic
> > that we already have would take care of it using the
> > INIT_MISSING_UDEV logic.
> > Either the WWID would be successfully retrieved eventually, in
> > which case the
> > path would be re-added to the previous map, or (depending on
> > configuration)
> > added to a new map or left alone. Or the failure is permanent, in
> > which case
> > multipathd would eventually give up and orphan the path. AFAICS
> > this would
> > be the "right thing" to do in all these different cases, without
> > any
> > additional logic.
> 
> This is where I don't fully agree. It means that we can be stuck
> waiting
> for a uevent to occur when the device has come back up, instead of
> just
> restoring it.  I would really like to keep as little code as possible
> that needs to get run before we restore a working path, because that
> could be, for instance, the last path to your root filesystem, and
> you
> can't touch any non-cached files on it, until you restore that path.
> 
> Even aside from the extreme case, multipathd is doing a lot of extra
> work, and quite possibly adding a lot of confusing log messages,
> simply
> because of an unfortunately timed change event.
>  
> > Note also that if a "reconfigure" was carried out in the presence
> > of
> > paths with changed WWID, the final outcome would likely be the same
> > that
> > my patch now achieves without "reconfigure".
> 
> Yeah. I just checked, and this is very broken, and something needs to
> be
> done to fix it.  If a device gets a change event while it's down, it
> will no longer have the udev properties necessary to not be
> blacklisted,
> so the device gets blacklisted, and ignored.  Even after it comes
> back
> up and gest another change event to restore these values, multipathd
> still ignores it, because the device was blacklisted during its add
> event.

I wasn't aware of that.

> However, if you just set the wwid of a path to NULL and run
> reconfigure,
> it will stay added to the map, and get it's wwid restored to the
> multipath device's wwid, because configure() calls map_discovery(),
> which ends up calling disassemble_map(). This will set a NULL path
> wwid
> to the multipath device wwid, since disassemble_map() assumes that
> NULL
> wwids just mean that multipathd couldn't get the wwid temporarily.

My thinking was that reconfigure calls path_discovery(), which would
call pathinfo() on all available paths again. I understand now - if
there was an error processing the last uevent for a device, the
information in the udev DB will still be incomplete, and
path_discovery() will obtain the same broken information, possibly
blacklisting the device. I thought the WWID might then be restored by
the INIT_MISSING_UDEV logic, but disassemble_map() would almost
certainly come first. I'm not sure I like it that disassemble_map()
tries to fill in path information. It's ok to do this for paths
that haven't been detected at all (pp == NULL case) but in case of
paths that are present in the udev db, I'm uncertain.

This would also affect your treatment of "WWID changed to zero", no?
Any call to setup_multipath() or update_multipath() would call
disassemble_map(), which would possibly mess with the path's wwid...


> 
> > I case I've come to the wrong conclusions because I overlooked
> > something
> > essential, please tell me.
> > 
> > Going one step futher, I've actually come to think differently
> > about the
> > "fallback logic" for the case that no WWID can be obtained from
> > udev. I
> > believe now that such fallback logic should _not_ be used. The
> > point is not
> > to derive _some_ WWID, but _the right one_, and that's udev's job.
> > But udev
> > can be customized in complex ways that multipathd has no idea
> > about.
> > In the worst case, we'd receive some WWIDs from udev and some from
> > our
> > own logic, and combine paths into a map which wouldn't acutally
> > belong
> > together. Therefore I vote for ripping out the fallback logic
> > altogether
> > and depend on udev exclusively for WWID generation. I haven't
> > included this
> > in the current patch set in order not to make it too controversial.
> > 
> > The only purpose for the fallback logic that I could see is to
> > provide
> > a configuration option to force multipathd to _always_ determine
> > the
> > WWID by itself, ignoring udev device properties.
> 
> I understand your concern.  There are currently safeguards (obviously
> not foolproof ones). The fallback wwid has to match the existing
> wwid,
> otherwise the path gets disabled. It seems very unlikely that a path
> configured to use the default uid_attribute, which switched to the
> fallback method and still got the same wwid, should actually have a
> different udev wwid than the one it previously had and that the
> fallback
> method still has.  Also, once a path starts using the fallback
> method,
> it clears uid_attribute, so that it keeps using the fallback method.
> 
> But to get back to dealing with changed wwids, I agree with removing
> an
> re-adding a device if it's wwid has changed. So, leaving that aside,
> the
> sticky question is "what to do with a path that has a NULL wwid?"
> 
> There are a number of options:
> 
> 1. Ignore the NULL wwid. This is what my patch 07 does, and I'd like
> to
> make the case for this yet again. 

You'd reverted this change in your patch 12, which confused me quite a
bit. What is your preference, really?

> I feel pretty sure that a NULL wwid on
> a change event is almost always going to occur because that change
> event
> happened when the path was down. If that's not the reason, then I
> believe it is either your reasons a) or c) from above. a) is not
> fixable. c) is not really our problem. It's a service to try saving
> the
> sysadmin from their own mistakes. But there is no way to make it
> foolproof. It is always possible for the device to get remapped and
> start getting IO before multipathd ever gets the uevent. The best we
> can
> guarantee is that we will eventually detect when this happens, report
> it, and stop it from doing more damage.  Given this, I think it's
> perfectly reasonable to just let NULL wwids slide, because that's
> ususally the right thing to do, and everything else makes the common
> case work worse, while still not providing a guarantee that the worst
> case is avoided. This is still my preferred solution.
> 
> 2. Fail the path on a NULL wwid. In the checker loop, when the path
> is
> up again, re-attempt to get the wwid.  However, since the udev
> information we have won't contain the new wwid, use the fallback
> information. This is my patch 12, and I agree that there could be
> issues
> with the fallback wwid being determined differently, although like I
> mentioned above, multipathd tries to deal with them.
> 
> 3. Fail the path on a NULL wwid. In the checker loop, when the path
> is
> up again, trigger a change uevent to get the new information. This
> delays restoring a path once it's up, and increases the number of
> things
> outside of multipathd's control that could go wrong which would keep
> the
> path from getting restored (udev timeouts, inability for udev to
> complete, because access to a necessary device is down).
> 
> 4. Some sort of hybrid of 2 and 3, where devices can either get their
> wwid from udev or directly from the device, and depending on how they
> get their wwid, by necessity they do different things. This is
> workable
> but a lot of code for something that is just a best-effort attempt to
> protect sysadmins from themselves.

You have argued well that 2. is best for re-acquiring a reasonable WWID
quickly. Anyway, I don't think it's healthy if the udev information is
wrong for a device, and remains wrong. Thus, IMO, another change event
should be triggered anyway, hoping to restore a state where udev
properties correctly identify the device. If the broken ID is really
just the result of bad timing as you suggest, that should likely be
successful. Some care may be needed to make sure that we don't confuse
ourselves with that self-generated uevent.

> 4. Completely remove the path, and try to re-add it.  This method
> will
> likely cause at least as much delay as 3, with an even larger chance
> that something goes wrong and keeps access from being restored.
> That's
> completely fine if the wwid has changed to something else, but I
> really
> don't like having to do all that work just because a change event
> occurred on a device that was down.
> 
> Thoughts?

Let's go for the removal and re-addition for the non-NULL changed WWID
case, and use the quick path for the NULL-WWID case (maybe we could
even try the "fallback" immediately in uev_update_path()?).

You have a more complete understanding of the whole issue than me, so I
trust that you'll come up with a v3 series addressing all these issues.

Regards
Martin

(*) This works only if the tool used to retrieve the VPDs support
reading from sysfs, of course, as sg_inq does (scsi_id does not,
currently).

-- 
Dr. Martin Wilck <mwilck@suse.com>, Tel. +49 (0)911 74053 2107
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)


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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/3] New approach at handling changed WWIDs
  2019-03-19 18:44   ` Martin Wilck
@ 2019-03-20  8:37     ` Martin Wilck
  2019-03-21 22:31       ` Benjamin Marzinski
  2019-03-25 22:27     ` Benjamin Marzinski
  1 sibling, 1 reply; 12+ messages in thread
From: Martin Wilck @ 2019-03-20  8:37 UTC (permalink / raw)
  To: Benjamin Marzinski, Hannes Reinecke; +Cc: dm-devel

On Tue, 2019-03-19 at 19:44 +0100, Martin Wilck wrote:
> On Tue, 2019-03-19 at 12:11 -0500, Benjamin Marzinski wrote:
> > On Mon, Mar 18, 2019 at 01:12:32PM +0100, Martin Wilck wrote:
> > > 
> > > Note also that if a "reconfigure" was carried out in the presence
> > > of
> > > paths with changed WWID, the final outcome would likely be the
> > > same
> > > that
> > > my patch now achieves without "reconfigure".
> > 
> > Yeah. I just checked, and this is very broken, and something needs
> > to
> > be
> > done to fix it.  If a device gets a change event while it's down,
> > it
> > will no longer have the udev properties necessary to not be
> > blacklisted,
> > so the device gets blacklisted, and ignored.  Even after it comes
> > back
> > up and gest another change event to restore these values,
> > multipathd
> > still ignores it, because the device was blacklisted during its add
> > event.
> 
> I wasn't aware of that.

We have a general problem in multipath-tools here. Our method of
blacklisting devices that don't have whitelisted udev properties
doesn't go together with the notion that udev may fail to set the
properties correctly, and the notion that paths shouldn't be removed or
failed (let alone blacklisted) without good reason.

Either we find a way to distinguish "devices that have incomplete udev
information because of temporary failure" and "devices that are missing
required udev properties permanently", or we must say goodbye to the
special treatment of blacklisting by property.

One obvious thing to do before blacklisting a path is to retry when we
encounter devices with missing properties. We can also check the
fallback UID methods - if they are successful and udev fails
repeatedly, the admin likely has messed up the udev rules.

Ben's approach to ignore WWIDs "changed to 0" at least temporarily
makes a lot of sense in this context. Paths that once used to have a
good WWID should be given up only after a reasonable number of retries.
Paths for which we'd never seen a valid WWID are treated by the
INIT_MISSING_UDEV logic.

Whatever we do, we should stop trying to "fix" the path WWID in
disassemble_map(). That's *so* against the separation of concerns
principle. In getuid(), we might check if a path with missing WWID is
already part of an existing multipath map, and then set the path WWID
from the map WWID as sort-of a last emergency fallback. But that, too,
should only be done during startup (assuming that a previous multipath
or multipathd instance had set up the map correctly, and that udev
information had been "lost" since then), and only after retrying as
described above.

Note that since by-property blacklisting was introduced in 2013,
significant progress has been made in other areas. We have blacklisting
by transport now, "find_multipaths", the "failed_wwids" logic that
avoids repeated attempts at setting up maps for busy devices, and the
INIT_MISSING_UDEV logic to deal with incomplete initialization. The
udev rules have been improved as well. So, doing away with "required
udev properties" may not be so dangerous, after all. 

Thoughts?
Martin

-- 
Dr. Martin Wilck <mwilck@suse.com>, Tel. +49 (0)911 74053 2107
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)


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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/3] New approach at handling changed WWIDs
  2019-03-20  8:37     ` Martin Wilck
@ 2019-03-21 22:31       ` Benjamin Marzinski
  2019-03-22 11:28         ` Martin Wilck
  0 siblings, 1 reply; 12+ messages in thread
From: Benjamin Marzinski @ 2019-03-21 22:31 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Wed, Mar 20, 2019 at 09:37:35AM +0100, Martin Wilck wrote:
> On Tue, 2019-03-19 at 19:44 +0100, Martin Wilck wrote:
> > On Tue, 2019-03-19 at 12:11 -0500, Benjamin Marzinski wrote:
> > > On Mon, Mar 18, 2019 at 01:12:32PM +0100, Martin Wilck wrote:
> > > > 
> > > > Note also that if a "reconfigure" was carried out in the presence
> > > > of
> > > > paths with changed WWID, the final outcome would likely be the
> > > > same
> > > > that
> > > > my patch now achieves without "reconfigure".
> > > 
> > > Yeah. I just checked, and this is very broken, and something needs
> > > to
> > > be
> > > done to fix it.  If a device gets a change event while it's down,
> > > it
> > > will no longer have the udev properties necessary to not be
> > > blacklisted,
> > > so the device gets blacklisted, and ignored.  Even after it comes
> > > back
> > > up and gest another change event to restore these values,
> > > multipathd
> > > still ignores it, because the device was blacklisted during its add
> > > event.
> > 
> > I wasn't aware of that.
> 
> We have a general problem in multipath-tools here. Our method of
> blacklisting devices that don't have whitelisted udev properties
> doesn't go together with the notion that udev may fail to set the
> properties correctly, and the notion that paths shouldn't be removed or
> failed (let alone blacklisted) without good reason.
> 
> Either we find a way to distinguish "devices that have incomplete udev
> information because of temporary failure" and "devices that are missing
> required udev properties permanently", or we must say goodbye to the
> special treatment of blacklisting by property.
> 
> One obvious thing to do before blacklisting a path is to retry when we
> encounter devices with missing properties. We can also check the
> fallback UID methods - if they are successful and udev fails
> repeatedly, the admin likely has messed up the udev rules.
> 
> Ben's approach to ignore WWIDs "changed to 0" at least temporarily
> makes a lot of sense in this context. Paths that once used to have a
> good WWID should be given up only after a reasonable number of retries.
> Paths for which we'd never seen a valid WWID are treated by the
> INIT_MISSING_UDEV logic.

ideally, we would be able to determine whether or not udev was able to
get all the necessary information. It would be nice to be notified if
scsi_id failed or udev timed out.
 
> Whatever we do, we should stop trying to "fix" the path WWID in
> disassemble_map(). That's *so* against the separation of concerns
> principle. In getuid(), we might check if a path with missing WWID is
> already part of an existing multipath map, and then set the path WWID
> from the map WWID as sort-of a last emergency fallback. But that, too,
> should only be done during startup (assuming that a previous multipath
> or multipathd instance had set up the map correctly, and that udev
> information had been "lost" since then), and only after retrying as
> described above.

We don't want to remove paths from multipath devices because multipathd
started up when the path was missing udev information. The udev
properties are trickier, but if we simply have a null WWID, it makes
sense to allow it as a last resort if the device otherwise appears to
have the same paths as it previously did. users can always run

# multipath -f

to remove the device. If it looks like some of the paths are supposed to
change on the device, we should quite possibly not include paths with a
null WWID, because we don't know what has changed.  But we can do this
someplace else than in disassemble_map(). 

> Note that since by-property blacklisting was introduced in 2013,
> significant progress has been made in other areas. We have blacklisting
> by transport now, "find_multipaths", the "failed_wwids" logic that
> avoids repeated attempts at setting up maps for busy devices, and the
> INIT_MISSING_UDEV logic to deal with incomplete initialization. The
> udev rules have been improved as well. So, doing away with "required
> udev properties" may not be so dangerous, after all. 
> 
> Thoughts?

Another option would be to do some extra work in reconfigure.  If we
held on to the old path, and cleaned up everything but the old udev
device and file descriptor, we could be sure that the kernel wouldn't
reuse that device major:minor while we were reconfiguring. If we got
some paths without their udev information, we would have the old udev
information to check against the new config, to see if the device should
be removed. Again, this works best if we could determine if we were
missing udev information.  Although in this case we could probably just
use any path that became blacklisted because of not having the necessary
property information.

-Ben

> Martin
> 
> -- 
> Dr. Martin Wilck <mwilck@suse.com>, Tel. +49 (0)911 74053 2107
> SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton
> HRB 21284 (AG Nürnberg)
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/3] New approach at handling changed WWIDs
  2019-03-21 22:31       ` Benjamin Marzinski
@ 2019-03-22 11:28         ` Martin Wilck
  2019-03-22 14:13           ` Benjamin Marzinski
  0 siblings, 1 reply; 12+ messages in thread
From: Martin Wilck @ 2019-03-22 11:28 UTC (permalink / raw)
  To: Benjamin Marzinski, mwilck+gmail; +Cc: dm-devel

On Thu, 2019-03-21 at 17:31 -0500, Benjamin Marzinski wrote:
> 
> ideally, we would be able to determine whether or not udev was able
> to
> get all the necessary information. It would be nice to be notified if
> scsi_id failed or udev timed out.

The latter (udev timeout) won't work without significant changes to
udev/systemd. Currently udevd simply kills hanging workers with
SIGKILL, and doesn't bother to send an "incomplete uevent" message to
monitor listeners.

What we *might* do in multipathd is listen for kernel uevents _and_
udev uevents, and figuring out possible problems by relating and
comparing them. It would be a non-trivial task; we'd have to deal with
the possibility that kernel events might get lost, or might have
happened before multipathd was started. During startup, this wouldn't
help us. Rather, it would enable us to react on events during runtime
which we currently miss. I see this as a feature enhancement -
possible, but really hard to get right, and not directly related to the
problems we are currently dealing with.

If we look at udev information for a block device (either during device
probing or uevent processing), and the WWID is not set but some other
properties (e.g. ID_PATH) are, we can be pretty sure that scsi_id or
sg_inq have failed during processing of the last uevent for that
device. If, in this case, we used our fallback action to retrieve the
WWID, we'd be able to determine if it was a very short-lived problem or
something more serious.
 
> > Whatever we do, we should stop trying to "fix" the path WWID in
> > disassemble_map(). That's *so* against the separation of concerns
> > principle. In getuid(), we might check if a path with missing WWID
> > is
> > already part of an existing multipath map, and then set the path
> > WWID
> > from the map WWID as sort-of a last emergency fallback. But that,
> > too,
> > should only be done during startup (assuming that a previous
> > multipath
> > or multipathd instance had set up the map correctly, and that udev
> > information had been "lost" since then), and only after retrying as
> > described above.
> 
> We don't want to remove paths from multipath devices because
> multipathd
> started up when the path was missing udev information. The udev
> properties are trickier, but if we simply have a null WWID, it makes
> sense to allow it as a last resort if the device otherwise appears to
> have the same paths as it previously did.

I agree, but I don't agree with filling in pp->wwid from mpp->wwid.

>  users can always run
> 
> # multipath -f
> 
> to remove the device. If it looks like some of the paths are supposed
> to
> change on the device, we should quite possibly not include paths with
> a
> null WWID, because we don't know what has changed.  But we can do
> this
> someplace else than in disassemble_map(). 

How would you determine that something is "supposed to change"?

> 
> > Note that since by-property blacklisting was introduced in 2013,
> > significant progress has been made in other areas. We have
> > blacklisting
> > by transport now, "find_multipaths", the "failed_wwids" logic that
> > avoids repeated attempts at setting up maps for busy devices, and
> > the
> > INIT_MISSING_UDEV logic to deal with incomplete initialization. The
> > udev rules have been improved as well. So, doing away with
> > "required
> > udev properties" may not be so dangerous, after all. 
> > 
> > Thoughts?
> 
> Another option would be to do some extra work in reconfigure.  If we
> held on to the old path, and cleaned up everything but the old udev
> device and file descriptor, we could be sure that the kernel wouldn't
> reuse that device major:minor while we were reconfiguring. If we got
> some paths without their udev information, we would have the old udev
> information to check against the new config, to see if the device
> should
> be removed. Again, this works best if we could determine if we were
> missing udev information.  Although in this case we could probably
> just
> use any path that became blacklisted because of not having the
> necessary
> property information.

IOW, we shouldn't blacklist these paths, which is what I was trying to
say. Your idea to hold the references until reconfigure() is finished
sounds clever to me.

The idea of blacklisting-by-missing-properties is to determine if
ID_SERIAL for a given WWID is _reliable_. It should be used if we get a
non-zero ID_SERIAL and at the same time none of the required
properties, e.g. ID_WWN. IMO, if this is the case, we can be certain
that scsi_id did *not* fail - after all, it was able to obtain
ID_SERIAL. OTOH, if neither ID_SERIAL nor ID_WWN is set, failure to
access the device is likely. Thus the solution here is simple: We
should apply "blacklisting by missing property" *only* if ID_SERIAL is
set, but ID_WWN is not.

Martin

-- 
Dr. Martin Wilck <mwilck@suse.com>, Tel. +49 (0)911 74053 2107
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)


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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/3] New approach at handling changed WWIDs
  2019-03-22 11:28         ` Martin Wilck
@ 2019-03-22 14:13           ` Benjamin Marzinski
  0 siblings, 0 replies; 12+ messages in thread
From: Benjamin Marzinski @ 2019-03-22 14:13 UTC (permalink / raw)
  To: Martin Wilck; +Cc: mwilck+gmail, dm-devel

On Fri, Mar 22, 2019 at 12:28:56PM +0100, Martin Wilck wrote:
> On Thu, 2019-03-21 at 17:31 -0500, Benjamin Marzinski wrote:
> > 
> > ideally, we would be able to determine whether or not udev was able
> > to
> > get all the necessary information. It would be nice to be notified if
> > scsi_id failed or udev timed out.
> 
> The latter (udev timeout) won't work without significant changes to
> udev/systemd. Currently udevd simply kills hanging workers with
> SIGKILL, and doesn't bother to send an "incomplete uevent" message to
> monitor listeners.
> 
> What we *might* do in multipathd is listen for kernel uevents _and_
> udev uevents, and figuring out possible problems by relating and
> comparing them. It would be a non-trivial task; we'd have to deal with
> the possibility that kernel events might get lost, or might have
> happened before multipathd was started. During startup, this wouldn't
> help us. Rather, it would enable us to react on events during runtime
> which we currently miss. I see this as a feature enhancement -
> possible, but really hard to get right, and not directly related to the
> problems we are currently dealing with.
> 
> If we look at udev information for a block device (either during device
> probing or uevent processing), and the WWID is not set but some other
> properties (e.g. ID_PATH) are, we can be pretty sure that scsi_id or
> sg_inq have failed during processing of the last uevent for that
> device. If, in this case, we used our fallback action to retrieve the
> WWID, we'd be able to determine if it was a very short-lived problem or
> something more serious.
>  
> > > Whatever we do, we should stop trying to "fix" the path WWID in
> > > disassemble_map(). That's *so* against the separation of concerns
> > > principle. In getuid(), we might check if a path with missing WWID
> > > is
> > > already part of an existing multipath map, and then set the path
> > > WWID
> > > from the map WWID as sort-of a last emergency fallback. But that,
> > > too,
> > > should only be done during startup (assuming that a previous
> > > multipath
> > > or multipathd instance had set up the map correctly, and that udev
> > > information had been "lost" since then), and only after retrying as
> > > described above.
> > 
> > We don't want to remove paths from multipath devices because
> > multipathd
> > started up when the path was missing udev information. The udev
> > properties are trickier, but if we simply have a null WWID, it makes
> > sense to allow it as a last resort if the device otherwise appears to
> > have the same paths as it previously did.
> 
> I agree, but I don't agree with filling in pp->wwid from mpp->wwid.

I'm fine with that.
 
> >  users can always run
> > 
> > # multipath -f
> > 
> > to remove the device. If it looks like some of the paths are supposed
> > to
> > change on the device, we should quite possibly not include paths with
> > a
> > null WWID, because we don't know what has changed.  But we can do
> > this
> > someplace else than in disassemble_map(). 
> 
> How would you determine that something is "supposed to change"?

Sorry. That was worded badly. For example, if we start up and determine
that mpatha should look just like the existing mpatha, except for a path
that in missing information, it makes sense to assume that path also
belongs. If configure determines that some of the paths that are in the
existing mpatha definitely do not belong there, then it shouldn't assume
the paths that we know nothing about do belong there.

So, if it appears that something has changed in a multipath device,
looking at the paths that we do have information for, we can't make
assumptions about the paths we don't have information for. 

> > 
> > > Note that since by-property blacklisting was introduced in 2013,
> > > significant progress has been made in other areas. We have
> > > blacklisting
> > > by transport now, "find_multipaths", the "failed_wwids" logic that
> > > avoids repeated attempts at setting up maps for busy devices, and
> > > the
> > > INIT_MISSING_UDEV logic to deal with incomplete initialization. The
> > > udev rules have been improved as well. So, doing away with
> > > "required
> > > udev properties" may not be so dangerous, after all. 
> > > 
> > > Thoughts?
> > 
> > Another option would be to do some extra work in reconfigure.  If we
> > held on to the old path, and cleaned up everything but the old udev
> > device and file descriptor, we could be sure that the kernel wouldn't
> > reuse that device major:minor while we were reconfiguring. If we got
> > some paths without their udev information, we would have the old udev
> > information to check against the new config, to see if the device
> > should
> > be removed. Again, this works best if we could determine if we were
> > missing udev information.  Although in this case we could probably
> > just
> > use any path that became blacklisted because of not having the
> > necessary
> > property information.
> 
> IOW, we shouldn't blacklist these paths, which is what I was trying to
> say. Your idea to hold the references until reconfigure() is finished
> sounds clever to me.
> 
> The idea of blacklisting-by-missing-properties is to determine if
> ID_SERIAL for a given WWID is _reliable_. It should be used if we get a
> non-zero ID_SERIAL and at the same time none of the required
> properties, e.g. ID_WWN. IMO, if this is the case, we can be certain
> that scsi_id did *not* fail - after all, it was able to obtain
> ID_SERIAL. OTOH, if neither ID_SERIAL nor ID_WWN is set, failure to
> access the device is likely. Thus the solution here is simple: We
> should apply "blacklisting by missing property" *only* if ID_SERIAL is
> set, but ID_WWN is not.

Sure.

-Ben
 
> Martin
> 
> -- 
> Dr. Martin Wilck <mwilck@suse.com>, Tel. +49 (0)911 74053 2107
> SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton
> HRB 21284 (AG Nürnberg)
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/3] New approach at handling changed WWIDs
  2019-03-19 18:44   ` Martin Wilck
  2019-03-20  8:37     ` Martin Wilck
@ 2019-03-25 22:27     ` Benjamin Marzinski
  2019-03-26  8:21       ` Martin Wilck
  1 sibling, 1 reply; 12+ messages in thread
From: Benjamin Marzinski @ 2019-03-25 22:27 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Tue, Mar 19, 2019 at 07:44:09PM +0100, Martin Wilck wrote:
> On Tue, 2019-03-19 at 12:11 -0500, Benjamin Marzinski wrote:
> > On Mon, Mar 18, 2019 at 01:12:32PM +0100, Martin Wilck wrote:
> > 
> > d) and e) seem to me like by far the most likely scenarios, so doing
> > something suboptimal for them, in order to optimize the very unlikely
> > scenarios seems wrong.
> 
> You've worked on this far more than I did, so I trust your judgement.
> 
> One remark: With the kernel exporting the VPD pages in sysfs
> and my late "multipath -u" patch series, udev should be able to process
> uevents for path devices without a single actual device IO. (*) 
> While there are still possible causes for udev processing to get stuck,
> this would make it much less likely.

For reasons I don't understand, not all devices get a vpd_pg83 sysfs
file, even though they clearly have a page 0x83, since multipath and
sg_inq can read from it via ioctl.  I have a device like this. This is
quite possibly a kernel issue that should get fixed, but regardless,
it's been there for a while, and I just cheked and it still exists in
the 5.0.0-rc6 kernel.

> > > Note also that if a "reconfigure" was carried out in the presence
> > > of
> > > paths with changed WWID, the final outcome would likely be the same
> > > that
> > > my patch now achieves without "reconfigure".
> > 
> > Yeah. I just checked, and this is very broken, and something needs to
> > be
> > done to fix it.  If a device gets a change event while it's down, it
> > will no longer have the udev properties necessary to not be
> > blacklisted,
> > so the device gets blacklisted, and ignored.  Even after it comes
> > back
> > up and gest another change event to restore these values, multipathd
> > still ignores it, because the device was blacklisted during its add
> > event.
> 
> I wasn't aware of that.

I just found it out when I was checking to see what really happened on a
reconfigure with a null wwid path.

> > However, if you just set the wwid of a path to NULL and run
> > reconfigure,
> > it will stay added to the map, and get it's wwid restored to the
> > multipath device's wwid, because configure() calls map_discovery(),
> > which ends up calling disassemble_map(). This will set a NULL path
> > wwid
> > to the multipath device wwid, since disassemble_map() assumes that
> > NULL
> > wwids just mean that multipathd couldn't get the wwid temporarily.
> 
> My thinking was that reconfigure calls path_discovery(), which would
> call pathinfo() on all available paths again. I understand now - if
> there was an error processing the last uevent for a device, the
> information in the udev DB will still be incomplete, and
> path_discovery() will obtain the same broken information, possibly
> blacklisting the device. I thought the WWID might then be restored by
> the INIT_MISSING_UDEV logic, but disassemble_map() would almost
> certainly come first. I'm not sure I like it that disassemble_map()
> tries to fill in path information. It's ok to do this for paths
> that haven't been detected at all (pp == NULL case) but in case of
> paths that are present in the udev db, I'm uncertain.
> 
> This would also affect your treatment of "WWID changed to zero", no?
> Any call to setup_multipath() or update_multipath() would call
> disassemble_map(), which would possibly mess with the path's wwid...
> 

No, because my code doesn't change the wwid if moves to NULL, it simply
remembers the old wwid.  This only happens when you do a reconfigure,
because you are getting new paths. But regardless, I agree that we
should avoid setting the path wwid based on the map wwid.

> You'd reverted this change in your patch 12, which confused me quite a
> bit. What is your preference, really?

My preference really is my 07 patch, which is why I didn't simply merge
them to start with.

> Let's go for the removal and re-addition for the non-NULL changed WWID
> case, and use the quick path for the NULL-WWID case (maybe we could
> even try the "fallback" immediately in uev_update_path()?).

That was the whole point of my setting retriggers to the max. So that we
would immediately try the fallback method if we got a NULL wwid, after
we had successfully gotten it in the past.
 
> You have a more complete understanding of the whole issue than me, so I
> trust that you'll come up with a v3 series addressing all these issues.

I'd like to propose a different compromise; that is my option 1 (patch
07) along with triggering a uevent to update udev for NULL wwids. Here
is my biggest objection to option 2 (patch 12). In the scenario where we
have an incomplete uevent because of a uevent storm, multipathd will
suddenly fail a path that is working fine, simply because the machine is
under load.  I just don't relish the idea of explaining to a customer
that we failed their paths (likely making the situation even worse) even
though we didn't have to, simply because we were worried that the
customer might do something stupid, and we would have a better chance
(although not a certaintly) of protecting them from their own stupid
mistake if we unnecessarily failed working paths.

This might be o.k. if we defaulted this behaviour to "off", but since it
is "on" by default, we are running a very real risk of failing perfectly
working paths, because we think our users might be stupid.

-Ben

> Regards
> Martin
> 
> (*) This works only if the tool used to retrieve the VPDs support
> reading from sysfs, of course, as sg_inq does (scsi_id does not,
> currently).

So, even when I run sg_inq on a device that does have the vpd_pg83 sysfs
file, it still does an ioctl. Do you know if that's just because I'm
using version 1.42, instead of 1.44?  As far as I know, sg_inq always
has done an ioctl.

> 
> -- 
> Dr. Martin Wilck <mwilck@suse.com>, Tel. +49 (0)911 74053 2107
> SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton
> HRB 21284 (AG Nürnberg)
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/3] New approach at handling changed WWIDs
  2019-03-25 22:27     ` Benjamin Marzinski
@ 2019-03-26  8:21       ` Martin Wilck
  0 siblings, 0 replies; 12+ messages in thread
From: Martin Wilck @ 2019-03-26  8:21 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: dm-devel

On Mon, 2019-03-25 at 17:27 -0500, Benjamin Marzinski wrote:
> 
> > One remark: With the kernel exporting the VPD pages in sysfs
> > and my late "multipath -u" patch series, udev should be able to
> > process
> > uevents for path devices without a single actual device IO. (*) 
> > While there are still possible causes for udev processing to get
> > stuck,
> > this would make it much less likely.
> 
> For reasons I don't understand, not all devices get a vpd_pg83 sysfs
> file, even though they clearly have a page 0x83, since multipath and
> sg_inq can read from it via ioctl.  I have a device like this. This
> is
> quite possibly a kernel issue that should get fixed, but regardless,
> it's been there for a while, and I just cheked and it still exists in
> the 5.0.0-rc6 kernel.

This is intentional. The kernel applies conservative heuristics to
determine whether these VPDs are supported. See the comment in
scsi_device_supports_vpd(). Sometimes the kernel gets it wrong, usually
because the device claims to be a pre-SCSI_SPC_2 device. Such devices
should be fixed with the BLIST_TRY_VPD_PAGES device flag if they do
support the DI VPD.

OPEN-V devices are a notorious example. But meanwhile the blist flags
are in place for them.

Regards
Martin

-- 
Dr. Martin Wilck <mwilck@suse.com>, Tel. +49 (0)911 74053 2107
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)


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

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2019-03-26  8:21 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-03-18 12:12 [PATCH 0/3] New approach at handling changed WWIDs Martin Wilck
2019-03-18 12:12 ` [PATCH 1/3] multipathd: handle changed wwids by removal and addition Martin Wilck
2019-03-18 12:12 ` [PATCH 2/3] multipathd: remove "wwid_changed" path attribute Martin Wilck
2019-03-18 12:12 ` [PATCH 3/3] multipathd: ignore "disable_changed_wwids" Martin Wilck
2019-03-19 17:11 ` [PATCH 0/3] New approach at handling changed WWIDs Benjamin Marzinski
2019-03-19 18:44   ` Martin Wilck
2019-03-20  8:37     ` Martin Wilck
2019-03-21 22:31       ` Benjamin Marzinski
2019-03-22 11:28         ` Martin Wilck
2019-03-22 14:13           ` Benjamin Marzinski
2019-03-25 22:27     ` Benjamin Marzinski
2019-03-26  8:21       ` Martin Wilck

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox