* [PATCH v2 0/1] multipathd: verify udev WWIDs with the device before moving paths @ 2026-10-29 23:52 Brian Bunker 2026-10-29 23:52 ` [PATCH v2 1/1] " Brian Bunker 0 siblings, 1 reply; 6+ messages in thread From: Brian Bunker @ 2026-10-29 23:52 UTC (permalink / raw) To: dm-devel; +Cc: Benjamin Marzinski, Martin Wilck, Christophe Varoqui, Brian Bunker During an array controller failover on an iSCSI host, multipathd briefly put a path to one LUN into the map of another LUN, and I/O meant for the first LUN landed on the second. The host ran RHEL 9 device-mapper-multipath 0.8.7, but the code involved is essentially unchanged in master. See the v1 cover letter for the full sequence. Changes in v2, after Ben's review: - ev_add_path() no longer double-checks the WWID on every add. Ben was concerned about adding a check to perfectly normal adds, since a SCSI device can report several identifiers in VPD 0x83 and multipath's SG_IO code has to pick the same one udev does. The need_do_map argument of uev_add_path() and ev_add_path() is now enum path_add_mode, with a new PATH_ADD_REINIT value. It behaves like PATH_ADD_MAP, and is passed only when a path is re-added from uev_update_path(): after udev reported a changed WWID, or after udev data was missing at first. Only then is the WWID checked against the device. Ordinary adds never run the SG_IO check. - The uev_update_path() check is unchanged. It only runs when the WWID from udev differs from the cached one, and falls back to the old behavior if the device doesn't confirm the cached WWID. About how likely this is: we hit it because a test tool was opening and closing the sd devices read-write many times a second, and with udev's "watch" rule every close generates a change uevent that runs scsi_id against the device. That is far more udev traffic than a normal host generates, so we expect the window to be rare in practice. We don't know why the bad WWID was reported; the array may have answered the INQUIRY wrongly during the takeover, or the bad value may have arisen elsewhere in the udev path. What the patch does is stop multipathd from acting on a changed WWID without confirming it, since the result of acting on a wrong one is data going to the wrong LUN. Open points, as in v1: - If the SG_IO read fails, behavior is unchanged. Refusing the add in that case would be stricter; opinions welcome. - "multipathd reconfigure" builds maps through configure(), not ev_add_path(), so it isn't covered. Brian Bunker (1): multipathd: verify udev WWIDs with the device before moving paths multipathd/cli_handlers.c | 2 +- multipathd/main.c | 79 +++++++++++++++++++++++++++++++-------- multipathd/main.h | 12 +++++- 3 files changed, 76 insertions(+), 17 deletions(-) -- 2.56.0 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 1/1] multipathd: verify udev WWIDs with the device before moving paths 2026-10-29 23:52 [PATCH v2 0/1] multipathd: verify udev WWIDs with the device before moving paths Brian Bunker @ 2026-10-29 23:52 ` Brian Bunker 2026-10-30 18:09 ` Benjamin Marzinski 0 siblings, 1 reply; 6+ messages in thread From: Brian Bunker @ 2026-10-29 23:52 UTC (permalink / raw) To: dm-devel; +Cc: Benjamin Marzinski, Martin Wilck, Christophe Varoqui, Brian Bunker multipathd takes a path's WWID from udev. When a change uevent reports a different WWID, uev_update_path() removes the path from its map and re-adds it through uev_add_path(), which places it in whatever map owns the new WWID. Nothing checks the new value against the device itself; recheck_wwid only covers paths coming back up in the checker and "multipathd add path". If udev reports the wrong WWID, or the uevent is stale by the time it is processed, the path goes into the map of a different LUN and I/O for one LUN is silently sent to another. Use SG_IO to read VPD page 0x83 from the device in two places, for paths where can_recheck_wwid() is true: - In uev_update_path(), if the device still reports the cached WWID, ignore the udev value and leave the path where it is. - In ev_add_path(), when a path is being re-added because its udev data was missing or changed, refuse to add it if the device doesn't confirm its WWID. The path is orphaned, its WWID is cleared and it is marked INIT_MISSING_UDEV, so the checker retriggers udev (bounded by retrigger_tries) and the path is re-added from fresh data. To tell re-adds from ordinary adds, turn the need_do_map argument of uev_add_path() and ev_add_path() into enum path_add_mode, with a new PATH_ADD_REINIT value that behaves like PATH_ADD_MAP and also requests the WWID check. Ordinary adds are unchanged and never read the WWID from the device. If the SG_IO read fails, behavior is unchanged. Split the SG_IO read out of check_path_wwid_change() into get_sgio_wwid() so all the checks share it. Signed-off-by: Brian Bunker <brian@purestorage.com> --- multipathd/cli_handlers.c | 2 +- multipathd/main.c | 79 +++++++++++++++++++++++++++++++-------- multipathd/main.h | 12 +++++- 3 files changed, 76 insertions(+), 17 deletions(-) diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c index f5a13c46..9b4a04c2 100644 --- a/multipathd/cli_handlers.c +++ b/multipathd/cli_handlers.c @@ -673,7 +673,7 @@ cli_add_path (void *v, struct strbuf *reply, void *data) return 1; } } - return ev_add_path(pp, vecs, 1); + return ev_add_path(pp, vecs, PATH_ADD_MAP); blacklisted: append_strbuf_str(reply, "blacklisted\n"); condlog(2, "%s: path blacklisted", param); diff --git a/multipathd/main.c b/multipathd/main.c index 9bce4d6b..57a3dd9e 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -1086,14 +1086,16 @@ handle_path_wwid_change(struct path *pp, struct vectors *vecs) return removed; } -bool -check_path_wwid_change(struct path *pp) +/* + * Read the WWID directly from the device with SG_IO, bypassing udev + * and sysfs. Returns true and fills in wwid on success. + */ +static bool get_sgio_wwid(struct path *pp, char *wwid) { - char wwid[WWID_SIZE]; - int len = 0; + int len; size_t i; - if (!strlen(pp->wwid)) + if (pp->fd < 0) return false; /* Get the real fresh device wwid by sgio. sysfs still has old @@ -1111,6 +1113,15 @@ check_path_wwid_change(struct path *pp) /* no-op */ wwid[i] = '\0'; condlog(4, "%s: Got wwid %s by sgio", pp->dev, wwid); + return true; +} + +bool check_path_wwid_change(struct path *pp) +{ + char wwid[WWID_SIZE]; + + if (!strlen(pp->wwid) || !get_sgio_wwid(pp, wwid)) + return false; if (strncmp(wwid, pp->wwid, WWID_SIZE)) { condlog(0, "%s: wwid '%s' doesn't match wwid '%s' from device", @@ -1121,6 +1132,24 @@ check_path_wwid_change(struct path *pp) return false; } +/* + * udev reported a new WWID for a path. Returns true if the device + * itself still reports old_wwid, in which case the udev value must + * not be trusted. + */ +static bool device_kept_wwid(struct path *pp, const char *old_wwid) +{ + char wwid[WWID_SIZE]; + + if (!can_recheck_wwid(pp) || !get_sgio_wwid(pp, wwid) || + strncmp(wwid, old_wwid, WWID_SIZE)) + return false; + + condlog(0, "%s: ignoring wwid '%s' from udev, device still reports '%s'", + pp->dev, pp->wwid, wwid); + return true; +} + /* * uev_add_path can call uev_update_path, and uev_update_path can call * uev_add_path @@ -1128,7 +1157,8 @@ check_path_wwid_change(struct path *pp) static int uev_update_path (struct uevent *uev, struct vectors * vecs); static int -uev_add_path (struct uevent *uev, struct vectors * vecs, int need_do_map) +uev_add_path (struct uevent *uev, struct vectors * vecs, + enum path_add_mode mode) { struct path *pp; int ret = 0, i; @@ -1180,7 +1210,7 @@ uev_add_path (struct uevent *uev, struct vectors * vecs, int need_do_map) DI_ALL | DI_BLACKLIST); pthread_cleanup_pop(1); if (r == PATHINFO_OK && !prev_mpp) - ret = ev_add_path(pp, vecs, need_do_map); + ret = ev_add_path(pp, vecs, mode); else if (r == PATHINFO_OK && !strncmp(pp->wwid, prev_mpp->wwid, WWID_SIZE)) { /* @@ -1255,7 +1285,7 @@ uev_add_path (struct uevent *uev, struct vectors * vecs, int need_do_map) conf = get_multipath_config(); pp->checkint = conf->checkint; put_multipath_config(conf); - ret = ev_add_path(pp, vecs, need_do_map); + ret = ev_add_path(pp, vecs, mode); } else { condlog(0, "%s: failed to store path info, " "dropping event", @@ -1298,7 +1328,7 @@ sysfs_get_ro (struct path *pp) * 1: error */ int -ev_add_path (struct path * pp, struct vectors * vecs, int need_do_map) +ev_add_path (struct path * pp, struct vectors * vecs, enum path_add_mode mode) { struct multipath * mpp; char *params __attribute__((cleanup(cleanup_charp))) = NULL; @@ -1315,6 +1345,21 @@ ev_add_path (struct path * pp, struct vectors * vecs, int need_do_map) condlog(0, "%s: failed to get path uid", pp->dev); goto fail; /* leave path added to pathvec */ } + /* + * This path is being re-added because its udev data was missing or + * changed. The uevent may have been queued long before we got here, + * and adding a path to the map of a different LUN corrupts data, so + * confirm the WWID with the device first. On a mismatch, leave the + * path out and let the checker retrigger udev to get a fresh WWID. + */ + if (mode == PATH_ADD_REINIT && can_recheck_wwid(pp) && + check_path_wwid_change(pp)) { + condlog(0, "%s: not adding path, wwid '%s' not confirmed by device", + pp->dev, pp->wwid); + memset(pp->wwid, 0, WWID_SIZE); + pp->initialized = INIT_MISSING_UDEV; + goto fail; + } mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid); if (mpp && pp->size && mpp->size != pp->size) { condlog(0, "%s: failed to add new path %s, device size mismatch", mpp->alias, pp->dev); @@ -1375,7 +1420,7 @@ rescan: if (ro == 1) mpp->force_readonly = 1; - if (!need_do_map) + if (mode == PATH_ADD_NO_MAP) return 0; if (!dm_map_present(mpp->alias)) { @@ -1702,6 +1747,10 @@ uev_update_path (struct uevent *uev, struct vectors * vecs) strcpy(pp->wwid, wwid); else if (strlen(wwid) && strncmp(wwid, pp->wwid, WWID_SIZE) != 0) { + if (device_kept_wwid(pp, wwid)) { + strcpy(pp->wwid, wwid); + goto out; + } condlog(0, "%s: path wwid changed from '%s' to '%s'", uev->kernel, wwid, pp->wwid); ev_remove_path(pp, vecs, 1); @@ -1789,7 +1838,7 @@ out: } /* pp->initialized must not be INIT_PARTIAL if needs_reinit is set */ if (needs_reinit) - retval = uev_add_path(uev, vecs, 1); + retval = uev_add_path(uev, vecs, PATH_ADD_REINIT); return retval; } @@ -1905,13 +1954,13 @@ uev_trigger (struct uevent * uev, void * trigger_data) */ list_for_each_entry_safe(merge_uev, tmp, &uev->merge_node, node) { if (!strncmp(merge_uev->action, "add", 3)) - r += uev_add_path(merge_uev, vecs, 0); + r += uev_add_path(merge_uev, vecs, PATH_ADD_NO_MAP); if (!strncmp(merge_uev->action, "remove", 6)) r += uev_remove_path(merge_uev, vecs, 0); } if (!strncmp(uev->action, "add", 3)) - r += uev_add_path(uev, vecs, 1); + r += uev_add_path(uev, vecs, PATH_ADD_MAP); if (!strncmp(uev->action, "remove", 6)) r += uev_remove_path(uev, vecs, 1); if (!strncmp(uev->action, "change", 6)) @@ -3015,7 +3064,7 @@ update_uninitialized_path(struct vectors * vecs, struct path * pp) pthread_cleanup_pop(1); /* INIT_OK implies ret == PATHINFO_OK */ if (pp->initialized == INIT_OK) { - ev_add_path(pp, vecs, 1); + ev_add_path(pp, vecs, PATH_ADD_MAP); pp->tick = 1; } else if (ret == PATHINFO_SKIPPED) { int i; @@ -3036,7 +3085,7 @@ update_uninitialized_path(struct vectors * vecs, struct path * pp) CHECK_PATH_REMOVED : CHECK_PATH_SKIPPED; } - ev_add_path(pp, vecs, 1); + ev_add_path(pp, vecs, PATH_ADD_MAP); pp->tick = 1; } return CHECK_PATH_CHECKED; diff --git a/multipathd/main.h b/multipathd/main.h index b66208ec..34a12ad7 100644 --- a/multipathd/main.h +++ b/multipathd/main.h @@ -36,7 +36,17 @@ enum daemon_status wait_for_state_change_if(enum daemon_status oldstate, unsigned long ms); void schedule_reconfigure(enum force_reload_types requested_type); int need_to_delay_reconfig (struct vectors *); -int ev_add_path (struct path *, struct vectors *, int); +/* + * PATH_ADD_REINIT is PATH_ADD_MAP for a path that is being re-added + * because its udev data was missing or changed. Its WWID is verified + * with the device before the path is put into a map. + */ +enum path_add_mode { + PATH_ADD_NO_MAP, + PATH_ADD_MAP, + PATH_ADD_REINIT, +}; +int ev_add_path (struct path *, struct vectors *, enum path_add_mode); int ev_remove_path (struct path *, struct vectors *, int); int ev_add_map (char *, const char *, struct vectors *); int flush_map(struct multipath *, struct vectors *); -- 2.56.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/1] multipathd: verify udev WWIDs with the device before moving paths 2026-10-29 23:52 ` [PATCH v2 1/1] " Brian Bunker @ 2026-10-30 18:09 ` Benjamin Marzinski 2026-11-06 22:19 ` Martin Wilck 0 siblings, 1 reply; 6+ messages in thread From: Benjamin Marzinski @ 2026-10-30 18:09 UTC (permalink / raw) To: Brian Bunker; +Cc: dm-devel, Martin Wilck, Christophe Varoqui On Thu, Oct 29, 2026 at 04:52:41PM -0700, Brian Bunker wrote: > multipathd takes a path's WWID from udev. When a change uevent reports > a different WWID, uev_update_path() removes the path from its map and > re-adds it through uev_add_path(), which places it in whatever map owns > the new WWID. Nothing checks the new value against the device itself; > recheck_wwid only covers paths coming back up in the checker and > "multipathd add path". If udev reports the wrong WWID, or the uevent is > stale by the time it is processed, the path goes into the map of a > different LUN and I/O for one LUN is silently sent to another. > > Use SG_IO to read VPD page 0x83 from the device in two places, for > paths where can_recheck_wwid() is true: > > - In uev_update_path(), if the device still reports the cached WWID, > ignore the udev value and leave the path where it is. > > - In ev_add_path(), when a path is being re-added because its udev > data was missing or changed, refuse to add it if the device doesn't > confirm its WWID. The path is orphaned, its WWID is cleared and it > is marked INIT_MISSING_UDEV, so the checker retriggers udev (bounded > by retrigger_tries) and the path is re-added from fresh data. > > To tell re-adds from ordinary adds, turn the need_do_map argument of > uev_add_path() and ev_add_path() into enum path_add_mode, with a new > PATH_ADD_REINIT value that behaves like PATH_ADD_MAP and also requests > the WWID check. Ordinary adds are unchanged and never read the WWID > from the device. > > If the SG_IO read fails, behavior is unchanged. > > Split the SG_IO read out of check_path_wwid_change() into > get_sgio_wwid() so all the checks share it. > > Signed-off-by: Brian Bunker <brian@purestorage.com> Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com> ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/1] multipathd: verify udev WWIDs with the device before moving paths 2026-10-30 18:09 ` Benjamin Marzinski @ 2026-11-06 22:19 ` Martin Wilck 2026-11-09 18:57 ` Brian Bunker 2026-11-09 20:26 ` Benjamin Marzinski 0 siblings, 2 replies; 6+ messages in thread From: Martin Wilck @ 2026-11-06 22:19 UTC (permalink / raw) To: Benjamin Marzinski, Brian Bunker; +Cc: dm-devel, Christophe Varoqui On Fri, 2026-10-30 at 14:09 -0400, Benjamin Marzinski wrote: > On Thu, Oct 29, 2026 at 04:52:41PM -0700, Brian Bunker wrote: > > multipathd takes a path's WWID from udev. When a change uevent > > reports > > a different WWID, uev_update_path() removes the path from its map > > and > > re-adds it through uev_add_path(), which places it in whatever map > > owns > > the new WWID. Nothing checks the new value against the device > > itself; > > recheck_wwid only covers paths coming back up in the checker and > > "multipathd add path". If udev reports the wrong WWID, or the > > uevent is > > stale by the time it is processed, the path goes into the map of a > > different LUN and I/O for one LUN is silently sent to another. > > > > Use SG_IO to read VPD page 0x83 from the device in two places, for > > paths where can_recheck_wwid() is true: > > > > - In uev_update_path(), if the device still reports the cached > > WWID, > > ignore the udev value and leave the path where it is. > > > > - In ev_add_path(), when a path is being re-added because its udev > > data was missing or changed, refuse to add it if the device > > doesn't > > confirm its WWID. The path is orphaned, its WWID is cleared and > > it > > is marked INIT_MISSING_UDEV, so the checker retriggers udev > > (bounded > > by retrigger_tries) and the path is re-added from fresh data. > > > > To tell re-adds from ordinary adds, turn the need_do_map argument > > of > > uev_add_path() and ev_add_path() into enum path_add_mode, with a > > new > > PATH_ADD_REINIT value that behaves like PATH_ADD_MAP and also > > requests > > the WWID check. Ordinary adds are unchanged and never read the WWID > > from the device. > > > > If the SG_IO read fails, behavior is unchanged. > > > > Split the SG_IO read out of check_path_wwid_change() into > > get_sgio_wwid() so all the checks share it. > > > > Signed-off-by: Brian Bunker <brian@purestorage.com> > Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com> You will need convince me that this doesn't do more harm than good. We can't just use udev in one place and other methods elsewhere. I am open for a general redesign that uses sysfs for retrieving WWIDs, rather than udev. But using SG_IO seems wrong to me in general, because it can hang. If anything, we'd need to make this configurable, and we'd then need to use SG_IO consistently throughout the code (and SG_IO has significant disadvantages, as already mentioned). Also, SG_IO works for SCSI only. That may be a minor issue these days, because almost all disks handled by dm-multipath are SCSI disks, but at least formally we still support other block devices like NVMe and DASD. Unfortunately there's already a zoo of options for WWID detection which has grown over time. > About how likely this is: we hit it because a test tool was opening > and closing the sd devices read-write many times a second, and with > udev's "watch" rule every close generates a change uevent that runs > scsi_id against the device. I wouldn't call this a valid test. It's a deliberate abuse of udev functionality. If you do this, you need to disable udev's watch functionality, which is merely a convenience for users anyway. It's questionable if it's a useful feature on production servers in general. Thinking about it, I wonder if we should simply set "nowatch" for multipath members by default. AFAIU that would avoid the issue Brian encountered, at least in this test scenario. Regards Martin -- Dr. Martin Wilck <mwilck@suse.com> SUSE Software Solutions Germany GmbH, Frankenstr. 146, 90461 Nürnberg, Germany Geschäftsführer: Stefan Gaiser, Jochen Jaser, Abhinav Puri (HRB 36809,AG Nürnberg) ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/1] multipathd: verify udev WWIDs with the device before moving paths 2026-11-06 22:19 ` Martin Wilck @ 2026-11-09 18:57 ` Brian Bunker 2026-11-09 20:26 ` Benjamin Marzinski 1 sibling, 0 replies; 6+ messages in thread From: Brian Bunker @ 2026-11-09 18:57 UTC (permalink / raw) To: Martin Wilck Cc: Brian Bunker, Benjamin Marzinski, Christophe Varoqui, dm-devel On Fri, 2026-11-06, Martin Wilck wrote: > You will need convince me that this doesn't do more harm than good. > We can't just use udev in one place and other methods elsewhere. > > I am open for a general redesign that uses sysfs for retrieving > WWIDs, rather than udev. But using SG_IO seems wrong to me in general, > because it can hang. Agreed on SG_IO. v3 drops it: the re-add check compares the udev WWID with one built from the VPD page 0x83 data cached in sysfs, using the same get_vpd_uid()/parse_vpd_pg83() code as the existing sysfs fallback in get_uid(). It does no I/O on the device. On mixing methods, one thing I should have said earlier: on RHEL 9 the udev WWID isn't taken from sysfs. The RHEL sg3_utils package installs 55-scsi-sg3_id.rules as 61-scsi-sg3_id.rules ("need to run after 60-persistent-storage.rules"), so ID_SERIAL comes from "scsi_id --whitelisted", which sends INQUIRY over SG_IO; strace on our host shows it on every run. The bad WWID came from that INQUIRY. Where the sg3 rules run first, ID_SERIAL is derived from the same sysfs page the check reads, with the same designator selection when everything is at defaults, and can_recheck_wwid() limits the check to that case. So I'd argue it isn't another way of computing the WWID, but a comparison of udev's value with the data it is meant to come from. I also dropped the uev_update_path() check from v2. With cached data it could keep a path to a really remapped LUN in its old map, which is worse than the problem it was meant to fix. > I wouldn't call this a valid test. It's a deliberate abuse of udev > functionality. Fair. The tool doing this is ours, and we've changed it to open the devices read-only, which stops the flood of change events in our testing. The reason I'd still like multipathd to check the re-add is that when it goes wrong, the result is silent data corruption on another LUN, and nothing else in the stack notices. > Thinking about it, I wonder if we should simply set "nowatch" for > multipath members by default. I think that's worth doing regardless of this patch, and I'm happy to look at it separately. Brian ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/1] multipathd: verify udev WWIDs with the device before moving paths 2026-11-06 22:19 ` Martin Wilck 2026-11-09 18:57 ` Brian Bunker @ 2026-11-09 20:26 ` Benjamin Marzinski 1 sibling, 0 replies; 6+ messages in thread From: Benjamin Marzinski @ 2026-11-09 20:26 UTC (permalink / raw) To: Martin Wilck; +Cc: Brian Bunker, dm-devel, Christophe Varoqui On Fri, Nov 06, 2026 at 11:19:25PM +0100, Martin Wilck wrote: > On Fri, 2026-10-30 at 14:09 -0400, Benjamin Marzinski wrote: > > On Thu, Oct 29, 2026 at 04:52:41PM -0700, Brian Bunker wrote: > > > multipathd takes a path's WWID from udev. When a change uevent > > > reports > > > a different WWID, uev_update_path() removes the path from its map > > > and > > > re-adds it through uev_add_path(), which places it in whatever map > > > owns > > > the new WWID. Nothing checks the new value against the device > > > itself; > > > recheck_wwid only covers paths coming back up in the checker and > > > "multipathd add path". If udev reports the wrong WWID, or the > > > uevent is > > > stale by the time it is processed, the path goes into the map of a > > > different LUN and I/O for one LUN is silently sent to another. > > > > > > Use SG_IO to read VPD page 0x83 from the device in two places, for > > > paths where can_recheck_wwid() is true: > > > > > > - In uev_update_path(), if the device still reports the cached > > > WWID, > > > ignore the udev value and leave the path where it is. > > > > > > - In ev_add_path(), when a path is being re-added because its udev > > > data was missing or changed, refuse to add it if the device > > > doesn't > > > confirm its WWID. The path is orphaned, its WWID is cleared and > > > it > > > is marked INIT_MISSING_UDEV, so the checker retriggers udev > > > (bounded > > > by retrigger_tries) and the path is re-added from fresh data. > > > > > > To tell re-adds from ordinary adds, turn the need_do_map argument > > > of > > > uev_add_path() and ev_add_path() into enum path_add_mode, with a > > > new > > > PATH_ADD_REINIT value that behaves like PATH_ADD_MAP and also > > > requests > > > the WWID check. Ordinary adds are unchanged and never read the WWID > > > from the device. > > > > > > If the SG_IO read fails, behavior is unchanged. > > > > > > Split the SG_IO read out of check_path_wwid_change() into > > > get_sgio_wwid() so all the checks share it. > > > > > > Signed-off-by: Brian Bunker <brian@purestorage.com> > > Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com> > > You will need convince me that this doesn't do more harm than good. > We can't just use udev in one place and other methods elsewhere. I get your concern, but we already do this when recheck_wwid is set. Perhaps we could also gate this with that config option. > I am open for a general redesign that uses sysfs for retrieving > WWIDs, rather than udev. But using SG_IO seems wrong to me in general, > because it can hang. If anything, we'd need to make this configurable, > and we'd then need to use SG_IO consistently throughout the code (and > SG_IO has significant disadvantages, as already mentioned). Also, SG_IO > works for SCSI only. That may be a minor issue these days, because > almost all disks handled by dm-multipath are SCSI disks, but at least > formally we still support other block devices like NVMe and DASD. > > Unfortunately there's already a zoo of options for WWID detection which > has grown over time. > > > About how likely this is: we hit it because a test tool was opening > > and closing the sd devices read-write many times a second, and with > > udev's "watch" rule every close generates a change uevent that runs > > scsi_id against the device. > > I wouldn't call this a valid test. It's a deliberate abuse of udev > functionality. If you do this, you need to disable udev's watch > functionality, which is merely a convenience for users anyway. It's > questionable if it's a useful feature on production servers in general. > > Thinking about it, I wonder if we should simply set "nowatch" for > multipath members by default. AFAIU that would avoid the issue Brian > encountered, at least in this test scenario. I can't think of anything wrong with disabling that off the top of my head. Nothing should be directly opening these devices read-write once they are part of a multipath device. -Ben > Regards > Martin > > -- > Dr. Martin Wilck <mwilck@suse.com> > SUSE Software Solutions Germany GmbH, Frankenstr. 146, 90461 Nürnberg, > Germany > Geschäftsführer: Stefan Gaiser, Jochen Jaser, Abhinav Puri (HRB > 36809,AG Nürnberg) ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-11-09 20:26 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-29 23:52 [PATCH v2 0/1] multipathd: verify udev WWIDs with the device before moving paths Brian Bunker 2026-10-29 23:52 ` [PATCH v2 1/1] " Brian Bunker 2026-10-30 18:09 ` Benjamin Marzinski 2026-11-06 22:19 ` Martin Wilck 2026-11-09 18:57 ` Brian Bunker 2026-11-09 20:26 ` Benjamin Marzinski
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.