On a failed DM_DEVICE_REMOVE, dm_flush_map__() classified anything that
was not DM_IS_MPATH_YES as "removed externally" and returned DM_FLUSH_OK
without resuming the map it had just suspended. dm_is_mpath() also
returns DM_IS_MPATH_ERR (-1) when the status query itself fails, which
happens transiently under a heavy ioctl load (e.g. LUN-number recycling
plus ALUA transitions). A transient error was thus misread as a
successful external removal, and the map was left suspended
indefinitely, wedging later I/O node-wide via sync().

Only DM_IS_MPATH_NO now counts as "removed externally". A query error is
logged and falls through to the resume path instead of being reported as
success.

Signed-off-by: Suresh Thelkar <[email protected]>
---
 libmultipath/devmapper.c | 25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index e3870f59..a5570a85 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -1042,13 +1042,26 @@ int dm_flush_map__ (const char *mapname, int flags, int 
retries)
                        }
                        condlog(4, "multipath map %s removed", mapname);
                        return DM_FLUSH_OK;
-               } else if (dm_is_mpath(mapname) != DM_IS_MPATH_YES) {
-                       condlog(4, "multipath map %s removed externally",
-                               mapname);
-                       return DM_FLUSH_OK; /* raced. someone else removed it */
                } else {
-                       condlog(2, "failed to remove multipath map %s",
-                               mapname);
+                       int is_mpath = dm_is_mpath(mapname);
+
+                       if (is_mpath == DM_IS_MPATH_NO) {
+                               condlog(4, "multipath map %s removed 
externally",
+                                       mapname);
+                               return DM_FLUSH_OK; /* raced. someone else 
removed it */
+                       }
+                       /*
+                        * A query error (DM_IS_MPATH_ERR) must not be treated
+                        * as "removed externally": under an ioctl storm the
+                        * status query can transiently fail, and returning
+                        * DM_FLUSH_OK here would leave the map suspended.
+                        */
+                       if (is_mpath == DM_IS_MPATH_ERR)
+                               condlog(1, "%s: unable to verify map state 
after failed remove",
+                                       mapname);
+                       else
+                               condlog(2, "failed to remove multipath map %s",
+                                       mapname);
                        if ((flags & DMFL_SUSPEND) && queue_if_no_path != -1) {
                                dm_simplecmd_noflush(DM_DEVICE_RESUME,
                                                     mapname, udev_flags);
-- 
2.43.0


Reply via email to