Re: [PATCH 2/2] iio: iio-mux: kzalloc instead of devm_kzalloc to ensure page alignment

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 02 Dec 2024 16:11:08 +0100
Matteo Martelli <matteomartelli3@xxxxxxxxx> wrote:

> During channel configuration, the iio-mux driver allocates a page with
> devm_kzalloc(PAGE_SIZE) to read channel ext_info. However, the resulting
> buffer points to an offset of the page due to the devres header sitting
> at the beginning of the allocated area. This leads to failure in the
> provider driver when sysfs_emit* helpers are used to format the ext_info
> attributes.
> 
> Switch to plain kzalloc version. The devres version is not strictly
> necessary as the buffer is only accessed during the channel
> configuration phase. Rely on __free cleanup to deallocate the buffer.
> Also, move the ext_info handling into a new function to have the page
> buffer definition and assignment in one statement as suggested by
> cleanup documentation.
> 
> Signed-off-by: Matteo Martelli <matteomartelli3@xxxxxxxxx>
This seems fine to me, but the diff ended up a bit complex, so I'd like
Peter to take a look as well before I apply it.

Do you have a board that is hitting this?  If so, a fixes tag is definitely
appropriate. I think it is probably appropriate even it not.

Jonathan

> ---
>  drivers/iio/multiplexer/iio-mux.c | 84 +++++++++++++++++++++------------------
>  1 file changed, 46 insertions(+), 38 deletions(-)
> 
> diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c
> index 2953403bef53bbe47a97a8ab1c475ed88d7f86d2..c309d991490c63ba4299f1cda7102f10dcf54982 100644
> --- a/drivers/iio/multiplexer/iio-mux.c
> +++ b/drivers/iio/multiplexer/iio-mux.c
> @@ -7,6 +7,7 @@
>   * Author: Peter Rosin <peda@xxxxxxxxxx>
>   */
>  
> +#include <linux/cleanup.h>
>  #include <linux/err.h>
>  #include <linux/iio/consumer.h>
>  #include <linux/iio/iio.h>
> @@ -237,49 +238,18 @@ static ssize_t mux_write_ext_info(struct iio_dev *indio_dev, uintptr_t private,
>  	return ret;
>  }
>  
> -static int mux_configure_channel(struct device *dev, struct mux *mux,
> -				 u32 state, const char *label, int idx)
> +static int mux_configure_chan_ext_info(struct device *dev, struct mux *mux,
> +				       int idx, int num_ext_info)
>  {
>  	struct mux_child *child = &mux->child[idx];
> -	struct iio_chan_spec *chan = &mux->chan[idx];
>  	struct iio_chan_spec const *pchan = mux->parent->channel;
> -	char *page = NULL;
> -	int num_ext_info;
>  	int i;
>  	int ret;
>  
> -	chan->indexed = 1;
> -	chan->output = pchan->output;
> -	chan->datasheet_name = label;
> -	chan->ext_info = mux->ext_info;
> -
> -	ret = iio_get_channel_type(mux->parent, &chan->type);
> -	if (ret < 0) {
> -		dev_err(dev, "failed to get parent channel type\n");
> -		return ret;
> -	}
> -
> -	if (iio_channel_has_info(pchan, IIO_CHAN_INFO_RAW))
> -		chan->info_mask_separate |= BIT(IIO_CHAN_INFO_RAW);
> -	if (iio_channel_has_info(pchan, IIO_CHAN_INFO_SCALE))
> -		chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SCALE);
> -
> -	if (iio_channel_has_available(pchan, IIO_CHAN_INFO_RAW))
> -		chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_RAW);
> -
> -	if (state >= mux_control_states(mux->control)) {
> -		dev_err(dev, "too many channels\n");
> -		return -EINVAL;
> -	}
> -
> -	chan->channel = state;
> +	char *page __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> +	if (!page)
> +		return -ENOMEM;
>  
> -	num_ext_info = iio_get_channel_ext_info_count(mux->parent);
> -	if (num_ext_info) {
> -		page = devm_kzalloc(dev, PAGE_SIZE, GFP_KERNEL);
> -		if (!page)
> -			return -ENOMEM;
> -	}
>  	child->ext_info_cache = devm_kcalloc(dev,
>  					     num_ext_info,
>  					     sizeof(*child->ext_info_cache),
> @@ -318,8 +288,46 @@ static int mux_configure_channel(struct device *dev, struct mux *mux,
>  		child->ext_info_cache[i].size = ret;
>  	}
>  
> -	if (page)
> -		devm_kfree(dev, page);
> +	return 0;
> +}
> +
> +static int mux_configure_channel(struct device *dev, struct mux *mux, u32 state,
> +				 const char *label, int idx)
> +{
> +	struct iio_chan_spec *chan = &mux->chan[idx];
> +	struct iio_chan_spec const *pchan = mux->parent->channel;
> +	int num_ext_info;
> +	int ret;
> +
> +	chan->indexed = 1;
> +	chan->output = pchan->output;
> +	chan->datasheet_name = label;
> +	chan->ext_info = mux->ext_info;
> +
> +	ret = iio_get_channel_type(mux->parent, &chan->type);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to get parent channel type\n");
> +		return ret;
> +	}
> +
> +	if (iio_channel_has_info(pchan, IIO_CHAN_INFO_RAW))
> +		chan->info_mask_separate |= BIT(IIO_CHAN_INFO_RAW);
> +	if (iio_channel_has_info(pchan, IIO_CHAN_INFO_SCALE))
> +		chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SCALE);
> +
> +	if (iio_channel_has_available(pchan, IIO_CHAN_INFO_RAW))
> +		chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_RAW);
> +
> +	if (state >= mux_control_states(mux->control)) {
> +		dev_err(dev, "too many channels\n");
> +		return -EINVAL;
> +	}
> +
> +	chan->channel = state;
> +
> +	num_ext_info = iio_get_channel_ext_info_count(mux->parent);
> +	if (num_ext_info)
> +		return mux_configure_chan_ext_info(dev, mux, idx, num_ext_info);
>  
>  	return 0;
>  }
> 





[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux