free_multipath was passing FREE_PATHS to both free_pgvec() and free_pathvec(), which was wrong because a path could be referenced in both structures. This can't happen any more now, as free_pgvec() has lost the ability to free paths.
In general, free_multipath can't make any assumptions about whether a given path is referenced in mpp->paths, mpp->pg, or both. Therefore look first for paths that are referenced in mpp->pg but not in mpp->paths, clean them, and finally loop over mpp->paths. Signed-off-by: Martin Wilck <[email protected]> --- libmultipath/structs.c | 44 +++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/libmultipath/structs.c b/libmultipath/structs.c index 1ee29f6..29b62e4 100644 --- a/libmultipath/structs.c +++ b/libmultipath/structs.c @@ -298,8 +298,12 @@ void free_multipath_attributes(struct multipath *mpp) } void -free_multipath (struct multipath * mpp, enum free_path_mode free_paths) +free_multipath (struct multipath *mpp, enum free_path_mode free_paths) { + struct pathgroup *pgp; + struct path *pp; + int i, j; + if (!mpp) return; @@ -310,22 +314,36 @@ free_multipath (struct multipath * mpp, enum free_path_mode free_paths) mpp->alias = NULL; } - if (free_paths == KEEP_PATHS && mpp->pg) { - struct pathgroup *pgp; - struct path *pp; - int i, j; - - /* - * Make sure paths carry no reference to this mpp any more - */ - vector_foreach_slot(mpp->pg, pgp, i) { - vector_foreach_slot(pgp->paths, pp, j) - if (pp->mpp == mpp) + /* + * If free_paths == FREE_PATHS, free all paths. + * Otherwise, make sure no references to this mpp remain. + * + * First loop over mpp->pg and clean the paths that might + * be missing in mpp->paths. Then clean the rest + * by looping over mpp->paths. + */ + vector_foreach_slot(mpp->pg, pgp, i) { + vector_foreach_slot(pgp->paths, pp, j) { + if (find_slot(mpp->paths, pp) == -1) { + if (free_paths == FREE_PATHS) + free_path(pp); + else pp->mpp = NULL; + } } } - free_pathvec(mpp->paths, free_paths); + vector_foreach_slot(mpp->paths, pp, i) { + if (free_paths == FREE_PATHS) + free_path(pp); + else + pp->mpp = NULL; + } + + /* + * We've freed paths above already, use KEEP_PATHS here + */ + free_pathvec(mpp->paths, KEEP_PATHS); free_pgvec(mpp->pg); if (mpp->hwe) { vector_free(mpp->hwe); -- 2.52.0
