If check_path() exitted because the path's wwid changed and it was removed, checkerloop() wasn't decrementing the pathvec loop count. This caused the next path to be skipped by the checker loop. To solve this, make check_path() return -1 when a path is removed, make handle_uninitialized_path() also remove the path if it was blacklisted, and make checkerloop() just decrement the loop count when a path returns -1. Signed-off-by: Benjamin Marzinski <bmarzins@xxxxxxxxxx> --- multipathd/main.c | 33 ++++++++++++++++++++------------- multipathd/main.h | 2 +- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/multipathd/main.c b/multipathd/main.c index 0f763e29..e32af693 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -974,20 +974,24 @@ rescan_path(struct udev_device *ud) } } -void +/* Returns true if the path was removed */ +bool handle_path_wwid_change(struct path *pp, struct vectors *vecs) { struct udev_device *udd; static const char add[] = "add"; ssize_t ret; char dev[FILE_NAME_SIZE]; + bool removed = false; if (!pp || !pp->udev) - return; + return removed; strlcpy(dev, pp->dev, sizeof(dev)); udd = udev_device_ref(pp->udev); - if (!(ev_remove_path(pp, vecs, 1) & REMOVE_PATH_SUCCESS) && pp->mpp) { + if (ev_remove_path(pp, vecs, 1) & REMOVE_PATH_SUCCESS) { + removed = true; + } else if (pp->mpp) { pp->dmstate = PSTATE_FAILED; dm_fail_path(pp->mpp->alias, pp->dev_t); } @@ -997,6 +1001,7 @@ handle_path_wwid_change(struct path *pp, struct vectors *vecs) if (ret != sizeof(add) - 1) log_sysfs_attr_set_value(1, ret, "%s: failed to trigger add event", dev); + return removed; } bool @@ -2377,7 +2382,8 @@ check_mpp(struct vectors * vecs, struct multipath *mpp, unsigned int ticks) } /* - * Returns '1' if the path has been checked and '0' otherwise + * Returns '1' if the path has been checked, -1 if the path was removed, + * and '0' otherwise */ static int check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) @@ -2434,8 +2440,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) pp->dmstate == PSTATE_FAILED) && check_path_wwid_change(pp)) { condlog(0, "%s: path wwid change detected. Removing", pp->dev); - handle_path_wwid_change(pp, vecs); - return 0; + return handle_path_wwid_change(pp, vecs)? -1 : 0; } if (!pp->mpp->is_checked) { do_check_mpp(vecs, pp->mpp); @@ -2635,7 +2640,7 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks) } /* - * Returns -1 if the path was blacklisted, and 0 otherwise + * Returns -1 if the path was removed, and 0 otherwise */ static int handle_uninitialized_path(struct vectors * vecs, struct path * pp, @@ -2706,6 +2711,12 @@ handle_uninitialized_path(struct vectors * vecs, struct path * pp, ev_add_path(pp, vecs, 1); pp->tick = 1; } else if (ret == PATHINFO_SKIPPED) { + int i; + + condlog(1, "%s: path blacklisted. removing", pp->dev); + if ((i = find_slot(vecs->pathvec, (void *)pp)) != -1) + vector_del_slot(vecs->pathvec, i); + free_path(pp); return -1; } } @@ -2794,13 +2805,9 @@ checkerloop (void *ap) else rc = handle_uninitialized_path(vecs, pp, ticks); - if (rc < 0) { - condlog(1, "%s: check_path() failed, removing", - pp->dev); - vector_del_slot(vecs->pathvec, i); - free_path(pp); + if (rc < 0) i--; - } else + else num_paths += rc; if (++paths_checked % 128 == 0 && (lock_has_waiters(&vecs->lock) || diff --git a/multipathd/main.h b/multipathd/main.h index 4fcd6402..7aa93ca3 100644 --- a/multipathd/main.h +++ b/multipathd/main.h @@ -47,7 +47,7 @@ int setup_multipath(struct vectors * vecs, struct multipath * mpp); int update_multipath(struct vectors *vecs, char *mapname); int reload_and_sync_map(struct multipath *mpp, struct vectors *vecs); -void handle_path_wwid_change(struct path *pp, struct vectors *vecs); +bool handle_path_wwid_change(struct path *pp, struct vectors *vecs); bool check_path_wwid_change(struct path *pp); int finish_path_init(struct path *pp, struct vectors * vecs); int resize_map(struct multipath *mpp, unsigned long long size, -- 2.45.0