pp->pgindex is set in disassemble_map() when a map is parsed.
There are various possiblities for this index to become invalid.
pp->pgindex is only used in enable_group() and followover_should_fallback(),
and both callers take no action if it is 0, which is the right
thing to do if we don't know the path's pathgroup.

Make sure pp->pgindex is reset to 0 in various places:
- when it's orphaned,
- before (re)grouping paths,
- when we detect a bad mpp assignment in update_pathvec_from_dm().

The hunk in group_paths is mostly redundant with the hunk in free_pgvec(), but
because we're looping over pg->paths in the former and over pg->pgp in
the latter, I think it's better too play safe.

Fixes: 99db1bd ("[multipathd] re-enable disabled PG when at least one path is 
up")
Signed-off-by: Martin Wilck <mwi...@suse.com>
---
 libmultipath/pgpolicies.c  |  6 ++++++
 libmultipath/structs.c     | 12 +++++++++++-
 libmultipath/structs_vec.c |  8 ++++++++
 3 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/libmultipath/pgpolicies.c b/libmultipath/pgpolicies.c
index edc3c61..23ef2bd 100644
--- a/libmultipath/pgpolicies.c
+++ b/libmultipath/pgpolicies.c
@@ -127,6 +127,8 @@ fail:
 int group_paths(struct multipath *mp, int marginal_pathgroups)
 {
        vector normal, marginal;
+       struct path *pp;
+       int i;
 
        if (!mp->pg)
                mp->pg = vector_alloc();
@@ -138,6 +140,10 @@ int group_paths(struct multipath *mp, int 
marginal_pathgroups)
        if (!mp->pgpolicyfn)
                goto fail;
 
+       /* Reset pgindex, we're going to invalidate it */
+       vector_foreach_slot(mp->paths, pp, i)
+               pp->pgindex = 0;
+
        if (!marginal_pathgroups ||
            split_marginal_paths(mp->paths, &normal, &marginal) != 0) {
                if (mp->pgpolicyfn(mp, mp->paths) != 0)
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
index 61c8f32..4851725 100644
--- a/libmultipath/structs.c
+++ b/libmultipath/structs.c
@@ -239,8 +239,18 @@ free_pgvec (vector pgvec, enum free_path_mode free_paths)
        if (!pgvec)
                return;
 
-       vector_foreach_slot(pgvec, pgp, i)
+       vector_foreach_slot(pgvec, pgp, i) {
+
+               /* paths are going to be re-grouped, reset pgindex */
+               if (free_paths != FREE_PATHS) {
+                       struct path *pp;
+                       int j;
+
+                       vector_foreach_slot(pgp->paths, pp, j)
+                               pp->pgindex = 0;
+               }
                free_pathgroup(pgp, free_paths);
+       }
 
        vector_free(pgvec);
 }
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index d22056c..64c5ad5 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -139,6 +139,13 @@ static bool update_pathvec_from_dm(vector pathvec, struct 
multipath *mpp,
                                must_reload = true;
                                dm_fail_path(mpp->alias, pp->dev_t);
                                vector_del_slot(pgp->paths, j--);
+                               /*
+                                * pp->pgindex has been set in 
disassemble_map(),
+                                * which has probably been called just before 
for
+                                * mpp. So he pgindex relates to mpp and may be
+                                * wrong for pp->mpp. Invalidate it.
+                                */
+                               pp->pgindex = 0;
                                continue;
                        }
                        pp->mpp = mpp;
@@ -354,6 +361,7 @@ void orphan_path(struct path *pp, const char *reason)
 {
        condlog(3, "%s: orphan path, %s", pp->dev, reason);
        pp->mpp = NULL;
+       pp->pgindex = 0;
        uninitialize_path(pp);
 }
 
-- 
2.47.0


Reply via email to