Re: [PATCH v4 33/40] sh: mach-x3proto: optimize ilsel_enable()

Yury Norov <[email protected]>
Newsgroups gmane.linux.ports.sh.devel,gmane.linux.kernel
Message-ID <ZnWOfuIdjB5Hhf3M@yury-ThinkPad>
On Fri, Jun 21, 2024 at 10:48:44AM +0200, John Paul Adrian Glaubitz wrote:
> Hi Yury,
> 
> thanks for your patch!
> 
> On Thu, 2024-06-20 at 10:56 -0700, Yury Norov wrote:
> > Simplify ilsel_enable() by using find_and_set_bit().
> > 
> > Geert also pointed the bug in the old implementation:
> > 
> > 	I don't think the old code worked as intended: the first time
> > 	no free bit is found, bit would have been ILSEL_LEVELS, and
> > 	test_and_set_bit() would have returned false, thus terminating
> > 	the loop, and continuing with an out-of-range bit value? Hence
> > 	to work correctly, bit ILSEL_LEVELS of ilsel_level_map should
> > 	have been initialized to one?  Or am I missing something?
> > 
> > The new code does not have that issue.
> > 
> > CC: John Paul Adrian Glaubitz <[email protected]>
> > Signed-off-by: Yury Norov <[email protected]>
> > Reviewed-by: Geert Uytterhoeven <[email protected]>
> > ---
> >  arch/sh/boards/mach-x3proto/ilsel.c | 5 +++--
> >  1 file changed, 3 insertions(+), 2 deletions(-)
> > 
> > diff --git a/arch/sh/boards/mach-x3proto/ilsel.c b/arch/sh/boards/mach-x3proto/ilsel.c
> > index f0d5eb41521a..35b585e154f0 100644
> > --- a/arch/sh/boards/mach-x3proto/ilsel.c
> > +++ b/arch/sh/boards/mach-x3proto/ilsel.c
> > @@ -8,6 +8,7 @@
> >   */
> >  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> >  
> > +#include <linux/find_atomic.h>
> >  #include <linux/init.h>
> >  #include <linux/kernel.h>
> >  #include <linux/module.h>
> > @@ -99,8 +100,8 @@ int ilsel_enable(ilsel_source_t set)
> >  	}
> >  
> >  	do {
> > -		bit = find_first_zero_bit(&ilsel_level_map, ILSEL_LEVELS);
> > -	} while (test_and_set_bit(bit, &ilsel_level_map));
> > +		bit = find_and_set_bit(&ilsel_level_map, ILSEL_LEVELS);
> > +	} while (bit >= ILSEL_LEVELS);
> >  
> >  	__ilsel_enable(set, bit);
> 
> I will need to take a closer look at the whole code in ilsel_enable() to understand what's
> happening here. If Geert's explanation is correct, it sounds more like you're fixing a bug
> and saying you're optimizing the function in the patch subject would sound more like an
> euphemism.
> 
> Also, I think we should add a Fixes tag if possible in case your patch fixes an actual bug.
> 
> I will have a closer look over the weekend.

Hi John,

The problem is that if the ilsel_level_map if dense, the @bit
will be set to ILSEL_LEVELS. The following test_and_set_bit()
will therefore access a bit beyond the end of bitmap. Which in
turn is undef.

I'm not familiar to the subsystem as whole, so I can't say if it's
ever possible to have the ilsel_level_map all set. If you take a
look that would be great.

If this series will not move, the fix for this code would be:

  do {
          bit = find_first_zero_bit(&ilsel_level_map, ILSEL_LEVELS);
  } while (bit >= ILSEL_LEVELS || test_and_set_bit(bit, &ilsel_level_map));

It would work, but because find_first_zero_bit() is not designed to
work correctly in concurrent environment, it may trigger KCSAN and/or
return something non-relevant. See cover letter on this series for
details.

Thanks,
Yury
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.