After a failed DM_DEVICE_REMOVE the map was suspended earlier in dm_flush_map__(), and the recovery path issued a single fire-and-forget DM_DEVICE_RESUME whose result was ignored. If that resume ioctl failed, the map could be left suspended with no trace in the logs, which wedges any later task in uninterruptible D state and, because sync() walks every block device, hangs I/O node-wide until reboot.
Check the DM_DEVICE_RESUME return value and log at condlog(1) when it fails, so a leaked suspend is at least visible in the logs. The map is known to have been suspended at the start of the loop, so the ioctl return value is authoritative. Signed-off-by: Suresh Thelkar <[email protected]> --- libmultipath/devmapper.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c index a5570a85..85c552cf 100644 --- a/libmultipath/devmapper.c +++ b/libmultipath/devmapper.c @@ -1062,10 +1062,12 @@ int dm_flush_map__ (const char *mapname, int flags, int retries) 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); - } + /* Resume the map suspended above; log if the resume + * ioctl fails, so a leaked suspend is visible. */ + if ((flags & DMFL_SUSPEND) && queue_if_no_path != -1 && + !dm_simplecmd_noflush(DM_DEVICE_RESUME, mapname, udev_flags)) + condlog(1, "%s: failed to resume map after failed remove", + mapname); } if (retries) sleep(1); -- 2.43.0
