mbox series

[v2,00/10] gpio/pinctrl: replace gpiochip_is_requested() with a safer interface

Message ID 20231130134630.18198-1-brgl@bgdev.pl
Headers show
Series gpio/pinctrl: replace gpiochip_is_requested() with a safer interface | expand

Message

Bartosz Golaszewski Nov. 30, 2023, 1:46 p.m. UTC
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

While reworking the locking in GPIOLIB I realized that locking the
descriptor with users still calling gpiochip_is_requested() will still
be buggy as it returns a pointer to a string that can be freed whenever
the descriptor is released. Let's provide a safer alternative in the
form of a function that returns a copy of the label.

Use it in all drivers and remove gpiochip_is_requested().

I plan to provide this series in an immutable branch for the pinctrl and
baytrail trees to pull.

v1 -> v2:
- use DEFINE_CLASS() to register a destructor for making sure that the
  duplicated label doesn't leak out of the for_each loops even with
  break;

Bartosz Golaszewski (10):
  gpiolib: provide gpiochip_dup_line_label()
  gpio: wm831x: use gpiochip_dup_line_label()
  gpio: wm8994: use gpiochip_dup_line_label()
  gpio: stmpe: use gpiochip_dup_line_label()
  pinctrl: abx500: use gpiochip_dup_line_label()
  pinctrl: nomadik: use gpiochip_dup_line_label()
  pinctrl: baytrail: use gpiochip_dup_line_label()
  pinctrl: sppctl: use gpiochip_dup_line_label()
  gpiolib: use gpiochip_dup_line_label() in for_each helpers
  gpiolib: remove gpiochip_is_requested()

 drivers/gpio/gpio-stmpe.c                 |  6 +++-
 drivers/gpio/gpio-wm831x.c                | 14 ++++++---
 drivers/gpio/gpio-wm8994.c                | 13 +++++---
 drivers/gpio/gpiolib.c                    | 37 ++++++++++++++---------
 drivers/pinctrl/intel/pinctrl-baytrail.c  | 11 ++++---
 drivers/pinctrl/nomadik/pinctrl-abx500.c  |  9 ++++--
 drivers/pinctrl/nomadik/pinctrl-nomadik.c |  6 +++-
 drivers/pinctrl/sunplus/sppctl.c          | 10 +++---
 include/linux/gpio/driver.h               | 37 +++++++++++++++++------
 9 files changed, 95 insertions(+), 48 deletions(-)

Comments

Andy Shevchenko Nov. 30, 2023, 4:27 p.m. UTC | #1
On Thu, Nov 30, 2023 at 02:46:21PM +0100, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> 
> gpiochip_is_requested() not only has a misleading name but it returns
> a pointer to a string that is freed when the descriptor is released.
> 
> Provide a new helper meant to replace it, which returns a copy of the
> label string instead.

...

> + * Must not be called from atomic context.

Put the respective lockdep annotation.

...

> +	char *cpy;

So, why not naming it fully, i.e. "copy"?
Andy Shevchenko Nov. 30, 2023, 4:29 p.m. UTC | #2
On Thu, Nov 30, 2023 at 02:46:23PM +0100, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> 
> Use the new gpiochip_dup_line_label() helper to safely retrieve the
> descriptor label.

...

> -		seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio, label);
> +		seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio,
> +			   label ?: "Unrequested");

Haha, see previous comment (in previous email).
Andy Shevchenko Nov. 30, 2023, 4:36 p.m. UTC | #3
On Thu, Nov 30, 2023 at 02:46:27PM +0100, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> 
> Use the new gpiochip_dup_line_label() helper to safely retrieve the
> descriptor label.

...

>  		seq_printf(s,
>  			   " gpio-%-3d (%-20.20s) %s %s %s pad-%-3d offset:0x%03x mux:%d %s%s%s",
>  			   pin,
> -			   label,
> +			   label ?: "Unrequested",

This already fourth (?) duplication among drivers.
Perhaps you want a helper:
gpiochip_dup_line_label_fallback() // naming is up to you
which will return the same for everybody and we don't need to hunt for
the different meaning of "Unrequested".

Also the word "Unrequested" is a bit doubtful as it can be a label, right?
Something with special characters / spaces / etc would suit better?
In any case it might require to add a warning (?) to the GPIO lib core
when label gets assigned if it clashes with the "reserved" word.

>  			   val & BYT_INPUT_EN ? "  " : "in",
>  			   val & BYT_OUTPUT_EN ? "   " : "out",
>  			   str_hi_lo(val & BYT_LEVEL),
Andy Shevchenko Nov. 30, 2023, 4:40 p.m. UTC | #4
On Thu, Nov 30, 2023 at 02:46:29PM +0100, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> 
> Rework for_each_requested_gpio_in_range() to use the new helper to
> retrieve a dynamically allocated copy of the descriptor label and free
> it at the end of each iteration. We need to leverage the CLASS()'
> destructor to make sure that the label is freed even when breaking out
> of the loop.

...

>  const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned int offset);
>  char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset);
>  
> +

One blank line is enough.

> +struct _gpiochip_for_each_data {
> +	const char **label;
> +	int *i;

Why is this a signed?

> +};

...

> +DEFINE_CLASS(_gpiochip_for_each_data,
> +	     struct _gpiochip_for_each_data,
> +	     if (*_T.label) kfree(*_T.label),
> +	     ({ struct _gpiochip_for_each_data _data = { label, i };
> +	        *_data.i = 0;
> +		_data; }),

To me indentation of ({}) is quite weird. Where is this style being used
instead of more readable

	({
	   ...
	})

?
Bartosz Golaszewski Nov. 30, 2023, 5:39 p.m. UTC | #5
On Thu, Nov 30, 2023 at 5:36 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Thu, Nov 30, 2023 at 02:46:27PM +0100, Bartosz Golaszewski wrote:
> > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> >
> > Use the new gpiochip_dup_line_label() helper to safely retrieve the
> > descriptor label.
>
> ...
>
> >               seq_printf(s,
> >                          " gpio-%-3d (%-20.20s) %s %s %s pad-%-3d offset:0x%03x mux:%d %s%s%s",
> >                          pin,
> > -                        label,
> > +                        label ?: "Unrequested",
>
> This already fourth (?) duplication among drivers.
> Perhaps you want a helper:
> gpiochip_dup_line_label_fallback() // naming is up to you
> which will return the same for everybody and we don't need to hunt for
> the different meaning of "Unrequested".
>

IMO the overhead here is very small in return for better readability
(IOW: `label ?: "Unrequested"` is more readable than some function
named `gpiochip_dup_line_label_fallback()`). Given the string is in
.rodata anyway, I wouldn't be surprised if adding a helper resulted in
bigger code.

> Also the word "Unrequested" is a bit doubtful as it can be a label, right?
> Something with special characters / spaces / etc would suit better?
> In any case it might require to add a warning (?) to the GPIO lib core
> when label gets assigned if it clashes with the "reserved" word.
>

Agreed but this is a functional change in debugfs output. I know
debugfs is not considered stable but I didn't write it, I don't know
who's using it and I prefer to leave it be.

Bart

> >                          val & BYT_INPUT_EN ? "  " : "in",
> >                          val & BYT_OUTPUT_EN ? "   " : "out",
> >                          str_hi_lo(val & BYT_LEVEL),
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
Bartosz Golaszewski Nov. 30, 2023, 5:42 p.m. UTC | #6
On Thu, Nov 30, 2023 at 5:40 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Thu, Nov 30, 2023 at 02:46:29PM +0100, Bartosz Golaszewski wrote:
> > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> >
> > Rework for_each_requested_gpio_in_range() to use the new helper to
> > retrieve a dynamically allocated copy of the descriptor label and free
> > it at the end of each iteration. We need to leverage the CLASS()'
> > destructor to make sure that the label is freed even when breaking out
> > of the loop.
>
> ...
>
> >  const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned int offset);
> >  char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset);
> >
> > +
>
> One blank line is enough.
>
> > +struct _gpiochip_for_each_data {
> > +     const char **label;
> > +     int *i;
>
> Why is this a signed?
>

Some users use signed, others use unsigned. It doesn't matter as we
can't overflow it with the limit on the lines we have.

Bart

> > +};
>
> ...
>
> > +DEFINE_CLASS(_gpiochip_for_each_data,
> > +          struct _gpiochip_for_each_data,
> > +          if (*_T.label) kfree(*_T.label),
> > +          ({ struct _gpiochip_for_each_data _data = { label, i };
> > +             *_data.i = 0;
> > +             _data; }),
>
> To me indentation of ({}) is quite weird. Where is this style being used
> instead of more readable
>

There are no guidelines for this type of C abuse AFAIK. The macro may
be ugly but at least it hides the details from users which look nice
instead.

Bart

>         ({
>            ...
>         })
>
> ?
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
Bartosz Golaszewski Nov. 30, 2023, 5:48 p.m. UTC | #7
On Thu, Nov 30, 2023 at 5:27 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Thu, Nov 30, 2023 at 02:46:21PM +0100, Bartosz Golaszewski wrote:
> > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> >
> > gpiochip_is_requested() not only has a misleading name but it returns
> > a pointer to a string that is freed when the descriptor is released.
> >
> > Provide a new helper meant to replace it, which returns a copy of the
> > label string instead.
>
> ...
>
> > + * Must not be called from atomic context.
>
> Put the respective lockdep annotation.
>
> ...
>
> > +     char *cpy;
>
> So, why not naming it fully, i.e. "copy"?
>

Ekhm... let me quote the BigPinguin :)

--

C is a Spartan language, and your naming conventions should follow suit.
Unlike Modula-2 and Pascal programmers, C programmers do not use cute
names like ThisVariableIsATemporaryCounter. A C programmer would call that
variable ``tmp``, which is much easier to write, and not the least more
difficult to understand.

--

Bart

> --
> With Best Regards,
> Andy Shevchenko
>
>
Andy Shevchenko Nov. 30, 2023, 5:54 p.m. UTC | #8
On Thu, Nov 30, 2023 at 06:42:37PM +0100, Bartosz Golaszewski wrote:
> On Thu, Nov 30, 2023 at 5:40 PM Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> > On Thu, Nov 30, 2023 at 02:46:29PM +0100, Bartosz Golaszewski wrote:

...

> > >  const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned int offset);
> > >  char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset);
> > >
> > > +
> >
> > One blank line is enough.
> >
> > > +struct _gpiochip_for_each_data {
> > > +     const char **label;
> > > +     int *i;
> >
> > Why is this a signed?
> 
> Some users use signed, others use unsigned. It doesn't matter as we
> can't overflow it with the limit on the lines we have.

What's the problem to make it unsigned and be done with that for good?

> > > +};

...

> > > +DEFINE_CLASS(_gpiochip_for_each_data,
> > > +          struct _gpiochip_for_each_data,
> > > +          if (*_T.label) kfree(*_T.label),
> > > +          ({ struct _gpiochip_for_each_data _data = { label, i };
> > > +             *_data.i = 0;
> > > +             _data; }),
> >
> > To me indentation of ({}) is quite weird. Where is this style being used
> > instead of more readable
> 
> There are no guidelines for this type of C abuse AFAIK. The macro may
> be ugly but at least it hides the details from users which look nice
> instead.

If we can make it more readable for free, why not doing that way?

> >         ({
> >            ...
> >         })
> >
> > ?
Andy Shevchenko Nov. 30, 2023, 6 p.m. UTC | #9
On Thu, Nov 30, 2023 at 06:48:06PM +0100, Bartosz Golaszewski wrote:
> On Thu, Nov 30, 2023 at 5:27 PM Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> > On Thu, Nov 30, 2023 at 02:46:21PM +0100, Bartosz Golaszewski wrote:

...

> > > +     char *cpy;
> >
> > So, why not naming it fully, i.e. "copy"?
> >
> 
> Ekhm... let me quote the BigPinguin :)
> 
> --
> 
> C is a Spartan language, and your naming conventions should follow suit.
> Unlike Modula-2 and Pascal programmers, C programmers do not use cute
> names like ThisVariableIsATemporaryCounter. A C programmer would call that
> variable ``tmp``, which is much easier to write, and not the least more
> difficult to understand.

In contrary the cpy is more difficult to understand.

`git grep -lw cpy` vs. `git grep -lw copy` suggests that my variant
is preferable (even excluding tools/ and Documentation/).
Bartosz Golaszewski Nov. 30, 2023, 7:40 p.m. UTC | #10
On Thu, Nov 30, 2023 at 7:00 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Thu, Nov 30, 2023 at 06:48:06PM +0100, Bartosz Golaszewski wrote:
> > On Thu, Nov 30, 2023 at 5:27 PM Andy Shevchenko
> > <andriy.shevchenko@linux.intel.com> wrote:
> > > On Thu, Nov 30, 2023 at 02:46:21PM +0100, Bartosz Golaszewski wrote:
>
> ...
>
> > > > +     char *cpy;
> > >
> > > So, why not naming it fully, i.e. "copy"?
> > >
> >
> > Ekhm... let me quote the BigPinguin :)
> >
> > --
> >
> > C is a Spartan language, and your naming conventions should follow suit.
> > Unlike Modula-2 and Pascal programmers, C programmers do not use cute
> > names like ThisVariableIsATemporaryCounter. A C programmer would call that
> > variable ``tmp``, which is much easier to write, and not the least more
> > difficult to understand.
>
> In contrary the cpy is more difficult to understand.
>
> `git grep -lw cpy` vs. `git grep -lw copy` suggests that my variant
> is preferable (even excluding tools/ and Documentation/).
>

You are a thorough reviewer but man, are you also a bikeshedder. :)

Whatever, let's make it 'copy'.

Bart

> --
> With Best Regards,
> Andy Shevchenko
>
>
Bartosz Golaszewski Dec. 1, 2023, 10:54 a.m. UTC | #11
On Thu, Nov 30, 2023 at 5:27 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Thu, Nov 30, 2023 at 02:46:21PM +0100, Bartosz Golaszewski wrote:
> > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> >
> > gpiochip_is_requested() not only has a misleading name but it returns
> > a pointer to a string that is freed when the descriptor is released.
> >
> > Provide a new helper meant to replace it, which returns a copy of the
> > label string instead.
>
> ...
>
> > + * Must not be called from atomic context.
>
> Put the respective lockdep annotation.
>

What are you referring to?

Bart

> ...
>
> > +     char *cpy;
>
> So, why not naming it fully, i.e. "copy"?
>
> --
> With Best Regards,
> Andy Shevchenko
>
>