On Mon, 2025-12-01 at 22:02 -0500, Benjamin Marzinski wrote:
> When libmpathpersist notifies multipathd that a key has been
> registered,
> cli_setprstatus() calls pr_register_active_paths() with a flag to let
> it
> know that the paths are likely already registered, and it can skip
> re-registering them, as long as the number of active paths matches
> the
> number of registered keys. This shortcut can fail, causing multipathd
> to
> not register needed paths, if either a path becomes usable and
> another
> becomes unusable while libmpathpersist is running or if there already
> were registered keys for I_T Nexus's that don't correspond to path
> devices.
> 
> To make this shortcut work in cases like that, this commit adds a new
> multipathd command "setprstatus map <map> pathlist <pathlist>", where
> <pathlist> is a quoted, comma separated list of scsi path devices.
> libmpathpersist will send out the list of paths it registered the key
> on. pr_register_active_paths() will skip calling
> mpath_pr_event_handle()
> for paths on that list.
> 
> In order to deal with the possiblity of a preempt occuring while
> libmpathpersist was running, the code still needs to check that it
> has
> the expected number of keys.
> 
> Fixes: f7d6cd17 ("multipathd: Fix race while registering PR key")
> Signed-off-by: Benjamin Marzinski <[email protected]>
> ---
>  libmpathpersist/mpath_persist_int.c |  6 +--
>  libmpathpersist/mpath_updatepr.c    | 48 +++++++++++++++++------
>  libmpathpersist/mpathpr.h           |  4 +-
>  multipathd/callbacks.c              |  1 +
>  multipathd/cli.c                    |  1 +
>  multipathd/cli.h                    |  2 +
>  multipathd/cli_handlers.c           | 39 ++++++++++++++++--
>  multipathd/main.c                   | 61 +++++++++++++++++++--------
> --
>  multipathd/main.h                   |  3 +-
>  multipathd/multipathd.8.in          |  6 +++
>  10 files changed, 132 insertions(+), 39 deletions(-)
> 
> 
> diff --git a/multipathd/main.c b/multipathd/main.c
> index a7650639..2cd5c952 100644
> --- a/multipathd/main.c
> +++ b/multipathd/main.c
> @@ -630,28 +630,49 @@ flush_map_nopaths(struct multipath *mpp, struct
> vectors *vecs) {
>       return true;
>  }
>  
> -void pr_register_active_paths(struct multipath *mpp, bool
> check_nr_active)
> +/*
> + * If reg_paths in non-NULL, it is a vector of paths that
> libmpathpersist
> + * registered. If the number of registered keys is smaller than the
> number
> + * of registered paths, then likely a preempt that occurred while
> + * libmpathpersist was registering the key. As long as there are
> still some
> + * registered keys, treat the preempt as happening first, and make
> sure to
> + * register keys on all the paths. If the number of registered keys
> is at
> + * least as large as the number of registered paths, then no preempt
> happened,
> + * and multipathd does not need to re-register the paths that
> libmpathpersist
> + * handled
> + */
> +void pr_register_active_paths(struct multipath *mpp,
> +                           const struct vector_s *reg_paths)
>  {
> -     unsigned int i, j, nr_keys = 0;
> -     unsigned int nr_active = 0;
> +     unsigned int i, j, k, nr_keys = 0;
> +     unsigned int wanted_nr = VECTOR_SIZE(reg_paths);
>       struct path *pp;
>       struct pathgroup *pgp;
> -
> -     if (check_nr_active) {
> -             nr_active = count_active_paths(mpp);
> -             if (!nr_active)
> -                     return;
> -     }
> +     char *pathname;
>  
>       vector_foreach_slot (mpp->pg, pgp, i) {
>               vector_foreach_slot (pgp->paths, pp, j) {
>                       if (mpp->prflag == PR_UNSET)
>                               return;
> -                     if (pp->state == PATH_UP || pp->state ==
> PATH_GHOST) {
> -                             nr_keys = mpath_pr_event_handle(pp,
> nr_keys, nr_active);
> -                             if (check_nr_active && nr_keys ==
> nr_active)
> -                                     return;
> +                     if (pp->state != PATH_UP && pp->state !=
> PATH_GHOST)
> +                             continue;
> +                     if (wanted_nr && nr_keys) {
> +                             vector_foreach_slot(reg_paths,
> pathname, k) {
> +                                     if (strcmp(pp->dev,
> pathname) == 0 ||
> +                                         strcmp(pp->dev_t,
> pathname) == 0) {
> +                                             goto skip;
> +                                     }
> +                             }
> +                     }
> +                     nr_keys = mpath_pr_event_handle(pp, nr_keys,
> wanted_nr);
> +                     if (nr_keys && nr_keys < wanted_nr) {
> +                             /*
> +                              * Incorrect number of registered
> keys. Need
> +                              * to register all devices
> +                              */
> +                             wanted_nr = 0;
>                       }
> +skip:

This fails on Debian Sid with this error messsage:

main.c:677:3: error: label at end of compound statement is a C23
extension [-Werror,-Wc23-extensions]
  677 |                 }
      |            


[1] 
https://github.com/openSUSE/multipath-tools/actions/runs/20031717354/job/57442300023

Martin


Reply via email to