[dm-devel] [PATCH 16/72] libmultipath: make path_discovery() pthread_cancel()-safe

Benjamin Marzinski bmarzins at redhat.com
Wed Oct 30 14:53:33 UTC 2019


On Sat, Oct 12, 2019 at 09:27:57PM +0000, Martin Wilck wrote:
> From: Martin Wilck <mwilck at suse.com>
> 
> The udev_enumerate and udev_device refs wouldn't be released
> if the thread was cancelled. Fix it.
> 
> Signed-off-by: Martin Wilck <mwilck at suse.com>
> ---
>  libmultipath/discovery.c | 51 +++++++++++++++++++++++++++++++---------
>  1 file changed, 40 insertions(+), 11 deletions(-)
> 
> diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
> index e68b0e9f..d217ca92 100644
> --- a/libmultipath/discovery.c
> +++ b/libmultipath/discovery.c
> @@ -140,19 +140,47 @@ path_discover (vector pathvec, struct config * conf,
>  	return pathinfo(pp, conf, flag);
>  }
>  
> +static void cleanup_udev_enumerate_ptr(void *arg)
> +{
> +	struct udev_enumerate *ue;
> +
> +	if (!arg)
> +		return;
> +	ue = *((struct udev_enumerate**) arg);
> +	if (ue)
> +		(void)udev_enumerate_unref(ue);
> +}
> +
> +static void cleanup_udev_device_ptr(void *arg)
> +{
> +	struct udev_device *ud;
> +
> +	if (!arg)
> +		return;
> +	ud = *((struct udev_device**) arg);
> +	if (ud)
> +		(void)udev_device_unref(ud);
> +}
> +
>  int
>  path_discovery (vector pathvec, int flag)
>  {
> -	struct udev_enumerate *udev_iter;
> +	struct udev_enumerate *udev_iter = NULL;
>  	struct udev_list_entry *entry;
> -	struct udev_device *udevice;
> +	struct udev_device *udevice = NULL;
>  	struct config *conf;
> -	const char *devpath;
>  	int num_paths = 0, total_paths = 0, ret;
>  
> +	pthread_cleanup_push(cleanup_udev_enumerate_ptr, &udev_iter);
> +	pthread_cleanup_push(cleanup_udev_device_ptr, &udevice);
> +	conf = get_multipath_config();
> +	pthread_cleanup_push(put_multipath_config, conf);
> +
>  	udev_iter = udev_enumerate_new(udev);
> -	if (!udev_iter)
> -		return -ENOMEM;
> +	if (!udev_iter) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
>  
>  	if (udev_enumerate_add_match_subsystem(udev_iter, "block") < 0 ||
>  	    udev_enumerate_add_match_is_initialized(udev_iter) < 0 ||
> @@ -165,6 +193,8 @@ path_discovery (vector pathvec, int flag)
>  	udev_list_entry_foreach(entry,
>  				udev_enumerate_get_list_entry(udev_iter)) {
>  		const char *devtype;
> +		const char *devpath;
> +
>  		devpath = udev_list_entry_get_name(entry);
>  		condlog(4, "Discover device %s", devpath);
>  		udevice = udev_device_new_from_syspath(udev, devpath);
> @@ -175,19 +205,18 @@ path_discovery (vector pathvec, int flag)
>  		devtype = udev_device_get_devtype(udevice);
>  		if(devtype && !strncmp(devtype, "disk", 4)) {
>  			total_paths++;
> -			conf = get_multipath_config();
> -			pthread_cleanup_push(put_multipath_config, conf);

Why move grabbing the config RCU lock out of the loop? All things being
equal, it seems like we'd rather hold this for less time, and
rcu_read_lock() is designed to be lightweight, so calling it more times
shouldn't be an issue. 

-Ben

>  			if (path_discover(pathvec, conf,
>  					  udevice, flag) == PATHINFO_OK)
>  				num_paths++;
> -			pthread_cleanup_pop(1);
>  		}
> -		udev_device_unref(udevice);
> +		udevice = udev_device_unref(udevice);
>  	}
>  	ret = total_paths - num_paths;
> -out:
> -	udev_enumerate_unref(udev_iter);
>  	condlog(4, "Discovered %d/%d paths", num_paths, total_paths);
> +out:
> +	pthread_cleanup_pop(1);
> +	pthread_cleanup_pop(1);
> +	pthread_cleanup_pop(1);
>  	return ret;
>  }
>  
> -- 
> 2.23.0




More information about the dm-devel mailing list