|
|
5c2e41 |
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
5c2e41 |
From: Benjamin Marzinski <bmarzins@redhat.com>
|
|
|
5c2e41 |
Date: Mon, 18 Feb 2019 13:32:45 -0600
|
|
|
5c2e41 |
Subject: [PATCH] BZ 1673167: Fix miscounting active paths
|
|
|
5c2e41 |
|
|
|
5c2e41 |
When multipathd gets a change uevent, it calls pathinfo with DI_NOIO.
|
|
|
5c2e41 |
This sets the path state to the return value of path_offline(). If a
|
|
|
5c2e41 |
path is in the PATH_DOWN state but path_offline() returns PATH_UP, when
|
|
|
5c2e41 |
that path gets a change event, its state will get moved to PATH_UP
|
|
|
5c2e41 |
without either reinstating the path, or reloading the map. The next
|
|
|
5c2e41 |
call to check_path() will move the path back to PATH_DOWN. Since
|
|
|
5c2e41 |
check_path() simply increments and decrements nr_active instead of
|
|
|
5c2e41 |
calculating it based on the actual number of active paths, nr_active
|
|
|
5c2e41 |
will get decremented a second time for this failed path, potentially
|
|
|
5c2e41 |
putting the multipath device into recovery mode.
|
|
|
5c2e41 |
|
|
|
5c2e41 |
To avoid this situation, pathinfo() will now only set pp->state with
|
|
|
5c2e41 |
DI_NOIO if DI_CHECKER is also set. This isn't set in uev_update_path()
|
|
|
5c2e41 |
to avoid changing the path state in this case.
|
|
|
5c2e41 |
|
|
|
5c2e41 |
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
|
|
5c2e41 |
---
|
|
|
5c2e41 |
libmultipath/discovery.c | 11 ++++++-----
|
|
|
5c2e41 |
multipath/main.c | 2 +-
|
|
|
5c2e41 |
2 files changed, 7 insertions(+), 6 deletions(-)
|
|
|
5c2e41 |
|
|
|
5c2e41 |
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
|
|
|
5c2e41 |
index b267f07..5de087c 100644
|
|
|
5c2e41 |
--- a/libmultipath/discovery.c
|
|
|
5c2e41 |
+++ b/libmultipath/discovery.c
|
|
|
5c2e41 |
@@ -1914,11 +1914,12 @@ int pathinfo(struct path *pp, struct config *conf, int mask)
|
|
|
5c2e41 |
if (path_state == PATH_REMOVED)
|
|
|
5c2e41 |
goto blank;
|
|
|
5c2e41 |
else if (mask & DI_NOIO) {
|
|
|
5c2e41 |
- /*
|
|
|
5c2e41 |
- * Avoid any IO on the device itself.
|
|
|
5c2e41 |
- * Behave like DI_CHECKER in the "path unavailable" case.
|
|
|
5c2e41 |
- */
|
|
|
5c2e41 |
- pp->chkrstate = pp->state = path_state;
|
|
|
5c2e41 |
+ if (mask & DI_CHECKER)
|
|
|
5c2e41 |
+ /*
|
|
|
5c2e41 |
+ * Avoid any IO on the device itself.
|
|
|
5c2e41 |
+ * simply use the path_offline() return as its state
|
|
|
5c2e41 |
+ */
|
|
|
5c2e41 |
+ pp->chkrstate = pp->state = path_state;
|
|
|
5c2e41 |
return PATHINFO_OK;
|
|
|
5c2e41 |
}
|
|
|
5c2e41 |
|
|
|
5c2e41 |
diff --git a/multipath/main.c b/multipath/main.c
|
|
|
5c2e41 |
index 2c4054d..0545226 100644
|
|
|
5c2e41 |
--- a/multipath/main.c
|
|
|
5c2e41 |
+++ b/multipath/main.c
|
|
|
5c2e41 |
@@ -345,7 +345,7 @@ static int check_usable_paths(struct config *conf,
|
|
|
5c2e41 |
pp->udev = get_udev_device(pp->dev_t, DEV_DEVT);
|
|
|
5c2e41 |
if (pp->udev == NULL)
|
|
|
5c2e41 |
continue;
|
|
|
5c2e41 |
- if (pathinfo(pp, conf, DI_SYSFS|DI_NOIO) != PATHINFO_OK)
|
|
|
5c2e41 |
+ if (pathinfo(pp, conf, DI_SYSFS|DI_NOIO|DI_CHECKER) != PATHINFO_OK)
|
|
|
5c2e41 |
continue;
|
|
|
5c2e41 |
|
|
|
5c2e41 |
if (pp->state == PATH_UP &&
|
|
|
5c2e41 |
--
|
|
|
5c2e41 |
2.17.2
|
|
|
5c2e41 |
|