On Fri, Jul 12, 2024 at 07:14:55PM +0200, Martin Wilck wrote:
> We've removed partition mappings recursively since 83fb936 ("Correctly remove
> logical partition maps"). This was wrong, because kpartx doesn't create
> logical partitions as mappings onto the extended partition. Rather, logical
> partitions are created by kpartx as mappings to the multipath device, and
> afaics, this has always been the case. Therefore, the loop in
> do_foreach_partmaps() will detect all partition mappings (primary, extended,
> and logical) without recursion. At least since 4059e42 ("libmultipath: fix
> partition detection"), the recursion has actually been pointless, because
> is_mpath_part() would never have returned "true" for a pair of two partition
> mappings (one representing an extended partition and one a logical partition).
> 
> Avoiding the recursion has the additional benefit that the complexity of
> removing maps scales with N, where N is the number of dm devices, rather than
> with N^2. Also, it simplifies the code.
> 
> Split partmap_in_use() into two separate functions, mpath_in_use() (to be 
> called
> for multipath maps) and count_partitions(), which is called from
> do_foreach_partmaps().
> 
> Because do_foreach_partmaps() is now only legitimately called for multipath
> maps, quit early if called for another map type.
> 
> Signed-off-by: Martin Wilck <[email protected]>
> ---
>  libmultipath/devmapper.c          | 48 +++++++++++++++++++------------
>  libmultipath/devmapper.h          |  2 +-
>  libmultipath/libmultipath.version |  2 +-
>  multipathd/main.c                 |  2 +-
>  4 files changed, 33 insertions(+), 21 deletions(-)
> 
> diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> index 5749d63..d9d96be 100644
> --- a/libmultipath/devmapper.c
> +++ b/libmultipath/devmapper.c
> @@ -933,22 +933,37 @@ has_partmap(const char *name __attribute__((unused)),
>       return 1;
>  }
>  
> -int
> -partmap_in_use(const char *name, void *data)
> +/*
> + * This will be called from mpath_in_use, for each partition.
> + * If the partition itself in use, returns 1 immediately, causing
> + * do_foreach_partmaps() to stop iterating and return 1.
> + * Otherwise, increases the partition count.
> + */
> +static int count_partitions(const char *name, void *data)
> +{
> +     int *ret_count = (int *)data;
> +     int open_count = dm_get_opencount(name);
> +
> +     if (open_count)
> +             return 1;
> +     (*ret_count)++;
> +     return 0;
> +}
> +
> +int mpath_in_use(const char *name)
>  {
> -     int part_count, *ret_count = (int *)data;
>       int open_count = dm_get_opencount(name);
>  
> -     if (ret_count)
> -             (*ret_count)++;
> -     part_count = 0;
>       if (open_count) {
> -             if (do_foreach_partmaps(name, partmap_in_use, &part_count))
> -                     return 1;
> -             if (open_count != part_count) {
> -                     condlog(2, "%s: map in use", name);
> +             int part_count = 0;
> +
> +             if (do_foreach_partmaps(name, count_partitions, &part_count)) {
> +                     condlog(4, "%s: %s has open partitions", __func__, 
> name);
>                       return 1;
>               }
> +             condlog(4, "%s: %s: %d openers, %d partitions", __func__, name,
> +                     open_count, part_count);
> +             return open_count > part_count;
>       }
>       return 0;
>  }
> @@ -976,7 +991,7 @@ int _dm_flush_map (const char *mapname, int flags, int 
> retries)
>  
>       /* If you aren't doing a deferred remove, make sure that no
>        * devices are in use */
> -     if (!(flags & DMFL_DEFERRED) && partmap_in_use(mapname, NULL))
> +     if (!(flags & DMFL_DEFERRED) && mpath_in_use(mapname))
>                       return DM_FLUSH_BUSY;
>  
>       if ((flags & DMFL_SUSPEND) &&
> @@ -1314,7 +1329,7 @@ do_foreach_partmaps (const char *mapname,
>       char map_uuid[DM_UUID_LEN];
>       struct dm_info info;
>  
> -     if (libmp_mapinfo(DM_MAP_BY_NAME,
> +     if (libmp_mapinfo(DM_MAP_BY_NAME | MAPINFO_CHECK_UUID,

This patch is out of order. You add MAPINFO_CHECK_UUID in the next one.
Otherwise
Reviewed-by: Benjamin Marzinski <[email protected]>

-Ben

>                         (mapid_t) { .str = mapname },
>                         (mapinfo_t) { .uuid = map_uuid, .dmi = &info }) != 
> DMP_OK)
>               return 1;
> @@ -1381,12 +1396,9 @@ remove_partmap(const char *name, void *data)
>  {
>       struct remove_data *rd = (struct remove_data *)data;
>  
> -     if (dm_get_opencount(name)) {
> -             dm_remove_partmaps(name, rd->flags);
> -             if (!(rd->flags & DMFL_DEFERRED) && dm_get_opencount(name)) {
> -                     condlog(2, "%s: map in use", name);
> -                     return DM_FLUSH_BUSY;
> -             }
> +     if (!(rd->flags & DMFL_DEFERRED) && dm_get_opencount(name)) {
> +             condlog(2, "%s: map in use", name);
> +             return DM_FLUSH_BUSY;
>       }
>       condlog(4, "partition map %s removed", name);
>       dm_device_remove(name, rd->flags);
> diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
> index d01f9f2..6eb5ab9 100644
> --- a/libmultipath/devmapper.h
> +++ b/libmultipath/devmapper.h
> @@ -149,7 +149,7 @@ enum {
>       DM_FLUSH_BUSY,
>  };
>  
> -int partmap_in_use(const char *name, void *data);
> +int mpath_in_use(const char *name);
>  
>  enum {
>       DMFL_NONE      = 0,
> diff --git a/libmultipath/libmultipath.version 
> b/libmultipath/libmultipath.version
> index 54b5a23..649c1cb 100644
> --- a/libmultipath/libmultipath.version
> +++ b/libmultipath/libmultipath.version
> @@ -139,10 +139,10 @@ global:
>       libmultipath_exit;
>       libmultipath_init;
>       load_config;
> +     mpath_in_use;
>       need_io_err_check;
>       orphan_path;
>       parse_prkey_flags;
> -     partmap_in_use;
>       pathcount;
>       path_discovery;
>       path_get_tpgs;
> diff --git a/multipathd/main.c b/multipathd/main.c
> index 536974c..13af94e 100644
> --- a/multipathd/main.c
> +++ b/multipathd/main.c
> @@ -597,7 +597,7 @@ flush_map_nopaths(struct multipath *mpp, struct vectors 
> *vecs) {
>               return false;
>       }
>       if (mpp->flush_on_last_del == FLUSH_UNUSED &&
> -            partmap_in_use(mpp->alias, NULL) && is_queueing) {
> +         mpath_in_use(mpp->alias) && is_queueing) {
>               condlog(2, "%s: map in use and queueing, can't remove",
>                       mpp->alias);
>               return false;
> -- 
> 2.45.2


Reply via email to