On Wed, Dec 17, 2025 at 10:21:04PM +0100, Martin Wilck wrote:
> 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.

Like I said in 07/21, I don't think we should free paths here. The paths
linked from the multipath device are also in the pathvec. We should
always be freeing them from there, so we don't have a pathvec with freed
paths.

-Ben
 
> 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