public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Matti Vaittinen <mazziesaccount@gmail.com>
To: Jonathan Cameron <jic23@kernel.org>
Cc: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>,
	Lars-Peter Clausen <lars@metafoo.de>,
	linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] iio: sanity check available_scan_masks array
Date: Fri, 6 Oct 2023 09:05:08 +0300	[thread overview]
Message-ID: <fffbf40f-c2be-60d6-8a6f-4790a8e309ea@gmail.com> (raw)
In-Reply-To: <20231005163026.2c7707de@jic23-huawei>

On 10/5/23 18:30, Jonathan Cameron wrote:
> On Tue, 3 Oct 2023 12:49:45 +0300
> Matti Vaittinen <mazziesaccount@gmail.com> wrote:
> 
>> When IIO goes through the available scan masks in order to select the
>> best suiting one, it will just accept the first listed subset of channels
>> which meets the user's requirements. If driver lists a mask which is a
>> subset of some of the masks previously in the array of
>> avaliable_scan_masks, then the latter one will never be selected.
>>
>> Add a warning if driver registers masks which can't be used due to the
>> available_scan_masks-array ordering.
>>
>> Suggested-by: Jonathan Cameron <jic23@kernel.org>
>> Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>
> Hi Matti
> 
> Thanks for doing this.  A few comments inline + maybe we need to think
> about a unit test for the matching code. I feel we aren't pushing the
> corners of that in any drivers so far so it might bite us later.

I am extremely conservative what comes to adding unit tests. I have seen 
some projects where the amount of existing unit test code made code 
changes very much very slow - stopping people doing any improvements. 
Basically, no one wanted to touch the existing code unless it was 
absolutely must because even a minor code change caused several tests to 
break. OTOH, that unit test setup did not only test that end result of a 
function was expected - it did also check the calls done from the 
function to be tested - checking for example that the certain prints 
appeared with certain inputs and so on. That project stopped being fun 
very quickly...

But yes. After spending a while reading IIO code, I agree that _some_ 
parts of it could benefit from a few carefully designed unit tests. (And 
sorry, I haven't checked what tests are existing already - so may be 
there already is relevant tests) :) Channel data demuxing and the mask 
handling are indeed the first to come to my mind ;) I wouldn't dare to 
touch that part without some testing.

> Still that's a job for another day.

Hey, we need to have something for tomorrow, right? :)

> 
>>
>> ---
>> The change was suggested by Jonathan here:
>> https://lore.kernel.org/lkml/20230924170726.41443502@jic23-huawei/
>> ---
>>   drivers/iio/industrialio-core.c | 57 +++++++++++++++++++++++++++++++++
>>   1 file changed, 57 insertions(+)
>>
>> diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
>> index c77745b594bd..d4f37f4eeec0 100644
>> --- a/drivers/iio/industrialio-core.c
>> +++ b/drivers/iio/industrialio-core.c
>> @@ -1896,6 +1896,53 @@ static int iio_check_extended_name(const struct iio_dev *indio_dev)
>>   
>>   static const struct iio_buffer_setup_ops noop_ring_setup_ops;
>>   
>> +static void iio_sanity_check_avail_scan_masks(struct iio_dev *indio_dev)
>> +{
>> +	unsigned int num_masks, masklength, longs_per_mask;
>> +	const unsigned long *av_masks;
>> +	int i;
>> +
>> +	av_masks = indio_dev->available_scan_masks;
>> +	masklength = indio_dev->masklength;
>> +	longs_per_mask = BITS_TO_LONGS(masklength);
>> +
>> +	if (bitmap_empty(av_masks, masklength))
>> +		dev_warn(indio_dev->dev.parent, "empty scan mask\n");
> 
> They'd definitely notice this one as you'd never be able to enable the
> buffer - if someone hasn't tested that, then meh.  Still this function
> is called sanity_check so might as well check for insanity.
> 
> 
>> +
>> +	for (num_masks = 0; *av_masks; num_masks++)
> 
> I think we can't just check *av_masks - need bitmap_empty() as first
> long might be 0 but could be bits set in the next one.

Ah. In case where we have bitmap consisting of many longs. Indeed. By 
the way, I think I stole this check from the actual matching code - we 
should probably fix it as well.

>> +		av_masks += longs_per_mask;
> hmm. Makes me wonder if the available scan mask stuff actually works
> for large numbers of channels (so more than one long).

After you pointed out the problem in for-condition - it probably does 
not work for all cases.

>  I don't think
> we have any drivers that both have large channel counts and use
> available_scan_masks.   The code is there to support matching in this
> case but probably wants a selftest at somepoint to make sure it will work
> if such a device comes along...
> 
> 
>> +
>> +	if (num_masks < 2)
>> +		return;
> 
> Not sure it's worth bothering with this early exit route.  The loops
> will be trivial anyway if num_masks == 1.

I probably thought about the num_masks == 0 when adding this check. 
Decided we might just early exit while checking.

>> +
>> +	av_masks = indio_dev->available_scan_masks;
>> +
>> +	/*
>> +	 * Go through all the masks from first to one before the last, and see
>> +	 * that no mask found later from the available_scan_masks array is a
>> +	 * subset of mask found earlier. If this happens, then the mask found
>> +	 * later will never get used because scanning the array is stopped when
>> +	 * the first suitable mask is found. Drivers should order the array of
>> +	 * available masks in the order of preference (presumably the least
>> +	 * costy to access masks first).
>> +	 */
>> +	for (i = 0; i < num_masks - 1; i++) {
>> +		const unsigned long *mask1;
>> +		int j;
>> +
>> +		mask1 = av_masks + i * longs_per_mask;
>> +		for (j = i + 1; j < num_masks; j++) {
>> +			const unsigned long *mask2;
>> +
>> +			mask2 = av_masks + j * longs_per_mask;
>> +			if (bitmap_subset(mask2, mask1, masklength))
>> +				dev_warn(indio_dev->dev.parent,
>> +					 "available_scan_mask %d subset of %d. Never used\n",
>> +					 j, i);
>> +		}
>> +	}
>> +}
>> +
>>   int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
>>   {
>>   	struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
>> @@ -1934,6 +1981,16 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
>>   		goto error_unreg_debugfs;
>>   	}
>>   
>> +	/*
>> +	 * In order to not wreck utter havoc we just warn for now. Might want
>> +	 * to convert this to a failure after people have had time to act upon
>> +	 * the warning. It'd be nice to check this earlier, but we need the
>> +	 * iio_buffers_alloc_sysfs_and_mask() to have the masklength set.
> 
> It's not going to break anyone if they get this wrong, they will just waste time
> and possibly power reading too many channels!  So warn is appropriate I think.
> 
> I'm not sure the comment adds much in general so I'd slim it down or drop it
> from v2.

I'm fine with dropping the comment. My mindset is easily leaning too 
much on developing new drivers when I think of checks like this one. 
It'd be nice to get a noticeable kick immediately when developing a 
driver - but yes, one should be kicked just by the warning alone.

> 
>> +	 */
>> +	if (indio_dev->available_scan_masks)
>> +		iio_sanity_check_avail_scan_masks(indio_dev);
>> +
> One blank line is enough ;)

Again... Thanks!

>> +
>>   	ret = iio_device_register_sysfs(indio_dev);
>>   	if (ret) {
>>   		dev_err(indio_dev->dev.parent,
>>
>> base-commit: 5e99f692d4e32e3250ab18d511894ca797407aec

Yours,
	-- Matti

> 

-- 
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~


  reply	other threads:[~2023-10-06  6:05 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-03  9:49 [PATCH] iio: sanity check available_scan_masks array Matti Vaittinen
2023-10-05 15:30 ` Jonathan Cameron
2023-10-06  6:05   ` Matti Vaittinen [this message]
2023-10-06 11:10   ` Matti Vaittinen
2023-10-10 10:04     ` Jonathan Cameron
2023-10-10 12:56       ` Matti Vaittinen
2023-10-10 14:47         ` Jonathan Cameron
2023-10-16  9:46           ` Matti Vaittinen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=fffbf40f-c2be-60d6-8a6f-4790a8e309ea@gmail.com \
    --to=mazziesaccount@gmail.com \
    --cc=jic23@kernel.org \
    --cc=lars@metafoo.de \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=matti.vaittinen@fi.rohmeurope.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox