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


Reply via email to