[v2,4/5] gpiolib: cdev: reduce locking in gpio_desc_to_lineinfo()

Message ID 20231214095814.132400-5-warthog618@gmail.com
State New
Headers
Series gpiolib: cdev: relocate debounce_period_us |

Commit Message

Kent Gibson Dec. 14, 2023, 9:58 a.m. UTC
  Reduce the time holding the gpio_lock by snapshotting the desc flags,
rather than testing them individually while holding the lock.

Accept that the calculation of the used field is inherently racy, and
only check the availability of the line from pinctrl if other checks
pass, so avoiding the check for lines that are otherwise in use.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 drivers/gpio/gpiolib-cdev.c | 72 ++++++++++++++++++-------------------
 1 file changed, 35 insertions(+), 37 deletions(-)
  

Comments

andy@kernel.org Dec. 14, 2023, 3:10 p.m. UTC | #1
On Thu, Dec 14, 2023 at 05:58:13PM +0800, Kent Gibson wrote:
> Reduce the time holding the gpio_lock by snapshotting the desc flags,
> rather than testing them individually while holding the lock.
> 
> Accept that the calculation of the used field is inherently racy, and
> only check the availability of the line from pinctrl if other checks
> pass, so avoiding the check for lines that are otherwise in use.

...

> -	spin_lock_irqsave(&gpio_lock, flags);

Shouldn't this be covered by patch 1 (I mean conversion to scoped_guard()
instead of spinlock)?
  
Kent Gibson Dec. 14, 2023, 3:19 p.m. UTC | #2
On Thu, Dec 14, 2023 at 05:10:23PM +0200, Andy Shevchenko wrote:
> On Thu, Dec 14, 2023 at 05:58:13PM +0800, Kent Gibson wrote:
> > Reduce the time holding the gpio_lock by snapshotting the desc flags,
> > rather than testing them individually while holding the lock.
> >
> > Accept that the calculation of the used field is inherently racy, and
> > only check the availability of the line from pinctrl if other checks
> > pass, so avoiding the check for lines that are otherwise in use.
>
> ...
>
> > -	spin_lock_irqsave(&gpio_lock, flags);
>
> Shouldn't this be covered by patch 1 (I mean conversion to scoped_guard()
> instead of spinlock)?
>

Read the cover letter.
Doing that made the change larger, as flags gets removed then restored.
I had also thought the flag tests would get indented then unindented, but
if we use guard() the indentation should remain unchanged.

Can do it in 1 if you are happy with the flags declaration being
removed in patch 1 and restored in 4.

Cheers,
Kent.
  
andy@kernel.org Dec. 14, 2023, 3:27 p.m. UTC | #3
On Thu, Dec 14, 2023 at 11:19:01PM +0800, Kent Gibson wrote:
> On Thu, Dec 14, 2023 at 05:10:23PM +0200, Andy Shevchenko wrote:
> > On Thu, Dec 14, 2023 at 05:58:13PM +0800, Kent Gibson wrote:
> > > Reduce the time holding the gpio_lock by snapshotting the desc flags,
> > > rather than testing them individually while holding the lock.
> > >
> > > Accept that the calculation of the used field is inherently racy, and
> > > only check the availability of the line from pinctrl if other checks
> > > pass, so avoiding the check for lines that are otherwise in use.

...

> > > -	spin_lock_irqsave(&gpio_lock, flags);
> >
> > Shouldn't this be covered by patch 1 (I mean conversion to scoped_guard()
> > instead of spinlock)?
> >
> 
> Read the cover letter.
> Doing that made the change larger, as flags gets removed then restored.
> I had also thought the flag tests would get indented then unindented, but
> if we use guard() the indentation should remain unchanged.

I'm fine with that as I pointed out (have you received that mail? I had
problems with my mail server) the dflags is better semantically, so restoration
with _different_ name is fine.

> Can do it in 1 if you are happy with the flags declaration being
> removed in patch 1 and restored in 4.

Definitely.
  
Kent Gibson Dec. 14, 2023, 3:34 p.m. UTC | #4
On Thu, Dec 14, 2023 at 05:27:29PM +0200, Andy Shevchenko wrote:
> On Thu, Dec 14, 2023 at 11:19:01PM +0800, Kent Gibson wrote:
> > On Thu, Dec 14, 2023 at 05:10:23PM +0200, Andy Shevchenko wrote:
> > > On Thu, Dec 14, 2023 at 05:58:13PM +0800, Kent Gibson wrote:
> > > > Reduce the time holding the gpio_lock by snapshotting the desc flags,
> > > > rather than testing them individually while holding the lock.
> > > >
> > > > Accept that the calculation of the used field is inherently racy, and
> > > > only check the availability of the line from pinctrl if other checks
> > > > pass, so avoiding the check for lines that are otherwise in use.
>
> ...
>
> > > > -	spin_lock_irqsave(&gpio_lock, flags);
> > >
> > > Shouldn't this be covered by patch 1 (I mean conversion to scoped_guard()
> > > instead of spinlock)?
> > >
> >
> > Read the cover letter.
> > Doing that made the change larger, as flags gets removed then restored.
> > I had also thought the flag tests would get indented then unindented, but
> > if we use guard() the indentation should remain unchanged.
>
> I'm fine with that as I pointed out (have you received that mail? I had
> problems with my mail server) the dflags is better semantically, so restoration
> with _different_ name is fine.
>

I have noted that some of your replies have been delayed, and I can't be sure
of what I might not've received. I can't say I've seen one that mentions the
dflags name being preferable.

I prefer the plain flags name, if there is only one flag variable in the
function.

> > Can do it in 1 if you are happy with the flags declaration being
> > removed in patch 1 and restored in 4.
>
> Definitely.
>

Ok will re-arrange in v3.

Cheers,
Kent.
  
Kent Gibson Dec. 14, 2023, 3:46 p.m. UTC | #5
On Thu, Dec 14, 2023 at 11:34:44PM +0800, Kent Gibson wrote:
> On Thu, Dec 14, 2023 at 05:27:29PM +0200, Andy Shevchenko wrote:
> > On Thu, Dec 14, 2023 at 11:19:01PM +0800, Kent Gibson wrote:
> > > On Thu, Dec 14, 2023 at 05:10:23PM +0200, Andy Shevchenko wrote:
> > > > On Thu, Dec 14, 2023 at 05:58:13PM +0800, Kent Gibson wrote:
> > > > > Reduce the time holding the gpio_lock by snapshotting the desc flags,
> > > > > rather than testing them individually while holding the lock.
> > > > >
> > > > > Accept that the calculation of the used field is inherently racy, and
> > > > > only check the availability of the line from pinctrl if other checks
> > > > > pass, so avoiding the check for lines that are otherwise in use.
> >
> > ...
> >
> > > > > -	spin_lock_irqsave(&gpio_lock, flags);
> > > >
> > > > Shouldn't this be covered by patch 1 (I mean conversion to scoped_guard()
> > > > instead of spinlock)?
> > > >
> > >
> > > Read the cover letter.
> > > Doing that made the change larger, as flags gets removed then restored.
> > > I had also thought the flag tests would get indented then unindented, but
> > > if we use guard() the indentation should remain unchanged.
> >
> > I'm fine with that as I pointed out (have you received that mail? I had
> > problems with my mail server) the dflags is better semantically, so restoration
> > with _different_ name is fine.
> >
>
> I have noted that some of your replies have been delayed, and I can't be sure
> of what I might not've received. I can't say I've seen one that mentions the
> dflags name being preferable.
>
> I prefer the plain flags name, if there is only one flag variable in the
> function.
>
> > > Can do it in 1 if you are happy with the flags declaration being
> > > removed in patch 1 and restored in 4.
> >
> > Definitely.
> >
>
> Ok will re-arrange in v3.
>

Hang on - patch 4 has to use a scoped_guard(), so are you ok for patch 1
to introduce a guard(), to avoid changing the indentation, only to
replace it with a scoped_guard(), to perform the tests after releasing
the lock, in patch 4?

Cheers,
Kent.
  
andy@kernel.org Dec. 14, 2023, 3:50 p.m. UTC | #6
On Thu, Dec 14, 2023 at 11:34:44PM +0800, Kent Gibson wrote:
> On Thu, Dec 14, 2023 at 05:27:29PM +0200, Andy Shevchenko wrote:
> > On Thu, Dec 14, 2023 at 11:19:01PM +0800, Kent Gibson wrote:
> > > On Thu, Dec 14, 2023 at 05:10:23PM +0200, Andy Shevchenko wrote:
> > > > On Thu, Dec 14, 2023 at 05:58:13PM +0800, Kent Gibson wrote:

...

> > > > > -	spin_lock_irqsave(&gpio_lock, flags);
> > > >
> > > > Shouldn't this be covered by patch 1 (I mean conversion to scoped_guard()
> > > > instead of spinlock)?
> > >
> > > Read the cover letter.
> > > Doing that made the change larger, as flags gets removed then restored.
> > > I had also thought the flag tests would get indented then unindented, but
> > > if we use guard() the indentation should remain unchanged.
> >
> > I'm fine with that as I pointed out (have you received that mail? I had
> > problems with my mail server) the dflags is better semantically, so restoration
> > with _different_ name is fine.
> 
> I have noted that some of your replies have been delayed, and I can't be sure
> of what I might not've received. I can't say I've seen one that mentions the
> dflags name being preferable.
> 
> I prefer the plain flags name, if there is only one flag variable in the
> function.

I pointed out that lflags / dflags is kinda idiomatic internally to gpiolib*
code base. Using flags might feel misleading and otherwise will hint about
semantics of the variable. That said, I prefer it being named dflags.
  
andy@kernel.org Dec. 14, 2023, 3:52 p.m. UTC | #7
On Thu, Dec 14, 2023 at 11:46:54PM +0800, Kent Gibson wrote:
> On Thu, Dec 14, 2023 at 11:34:44PM +0800, Kent Gibson wrote:
> > On Thu, Dec 14, 2023 at 05:27:29PM +0200, Andy Shevchenko wrote:
> > > On Thu, Dec 14, 2023 at 11:19:01PM +0800, Kent Gibson wrote:
> > > > On Thu, Dec 14, 2023 at 05:10:23PM +0200, Andy Shevchenko wrote:
> > > > > On Thu, Dec 14, 2023 at 05:58:13PM +0800, Kent Gibson wrote:

...

> > > > > > -	spin_lock_irqsave(&gpio_lock, flags);
> > > > >
> > > > > Shouldn't this be covered by patch 1 (I mean conversion to scoped_guard()
> > > > > instead of spinlock)?
> > > >
> > > > Read the cover letter.
> > > > Doing that made the change larger, as flags gets removed then restored.
> > > > I had also thought the flag tests would get indented then unindented, but
> > > > if we use guard() the indentation should remain unchanged.
> > >
> > > I'm fine with that as I pointed out (have you received that mail? I had
> > > problems with my mail server) the dflags is better semantically, so restoration
> > > with _different_ name is fine.
> >
> > I have noted that some of your replies have been delayed, and I can't be sure
> > of what I might not've received. I can't say I've seen one that mentions the
> > dflags name being preferable.
> >
> > I prefer the plain flags name, if there is only one flag variable in the
> > function.
> >
> > > > Can do it in 1 if you are happy with the flags declaration being
> > > > removed in patch 1 and restored in 4.
> > >
> > > Definitely.
> >
> > Ok will re-arrange in v3.
> 
> Hang on - patch 4 has to use a scoped_guard(), so are you ok for patch 1
> to introduce a guard(), to avoid changing the indentation, only to
> replace it with a scoped_guard(), to perform the tests after releasing
> the lock, in patch 4?

Hmm... If we need to use scoped_guard() at the end, can we introduce it in
patch 1?
  
Kent Gibson Dec. 14, 2023, 3:53 p.m. UTC | #8
On Thu, Dec 14, 2023 at 11:46:54PM +0800, Kent Gibson wrote:
> On Thu, Dec 14, 2023 at 11:34:44PM +0800, Kent Gibson wrote:
> > On Thu, Dec 14, 2023 at 05:27:29PM +0200, Andy Shevchenko wrote:
> > > On Thu, Dec 14, 2023 at 11:19:01PM +0800, Kent Gibson wrote:
> > > > On Thu, Dec 14, 2023 at 05:10:23PM +0200, Andy Shevchenko wrote:
> > > > > On Thu, Dec 14, 2023 at 05:58:13PM +0800, Kent Gibson wrote:
> > > > > > Reduce the time holding the gpio_lock by snapshotting the desc flags,
> > > > > > rather than testing them individually while holding the lock.
> > > > > >
> > > > > > Accept that the calculation of the used field is inherently racy, and
> > > > > > only check the availability of the line from pinctrl if other checks
> > > > > > pass, so avoiding the check for lines that are otherwise in use.
> > >
> > > ...
> > >
> > > > > > -	spin_lock_irqsave(&gpio_lock, flags);
> > > > >
> > > > > Shouldn't this be covered by patch 1 (I mean conversion to scoped_guard()
> > > > > instead of spinlock)?
> > > > >
> > > >
> > > > Read the cover letter.
> > > > Doing that made the change larger, as flags gets removed then restored.
> > > > I had also thought the flag tests would get indented then unindented, but
> > > > if we use guard() the indentation should remain unchanged.
> > >
> > > I'm fine with that as I pointed out (have you received that mail? I had
> > > problems with my mail server) the dflags is better semantically, so restoration
> > > with _different_ name is fine.
> > >
> >
> > I have noted that some of your replies have been delayed, and I can't be sure
> > of what I might not've received. I can't say I've seen one that mentions the
> > dflags name being preferable.
> >
> > I prefer the plain flags name, if there is only one flag variable in the
> > function.
> >
> > > > Can do it in 1 if you are happy with the flags declaration being
> > > > removed in patch 1 and restored in 4.
> > >
> > > Definitely.
> > >
> >
> > Ok will re-arrange in v3.
> >
>
> Hang on - patch 4 has to use a scoped_guard(), so are you ok for patch 1
> to introduce a guard(), to avoid changing the indentation, only to
> replace it with a scoped_guard(), to perform the tests after releasing
> the lock, in patch 4?
>

Alternatively, I can move patch 4 to the top of the series.

Cheers,
Kent.
  
andy@kernel.org Dec. 14, 2023, 4:02 p.m. UTC | #9
On Thu, Dec 14, 2023 at 11:53:10PM +0800, Kent Gibson wrote:
> On Thu, Dec 14, 2023 at 11:46:54PM +0800, Kent Gibson wrote:
> > On Thu, Dec 14, 2023 at 11:34:44PM +0800, Kent Gibson wrote:
> > > On Thu, Dec 14, 2023 at 05:27:29PM +0200, Andy Shevchenko wrote:
> > > > On Thu, Dec 14, 2023 at 11:19:01PM +0800, Kent Gibson wrote:
> > > > > On Thu, Dec 14, 2023 at 05:10:23PM +0200, Andy Shevchenko wrote:
> > > > > > On Thu, Dec 14, 2023 at 05:58:13PM +0800, Kent Gibson wrote:

...

> > > > > > > -	spin_lock_irqsave(&gpio_lock, flags);
> > > > > >
> > > > > > Shouldn't this be covered by patch 1 (I mean conversion to scoped_guard()
> > > > > > instead of spinlock)?
> > > > >
> > > > > Read the cover letter.
> > > > > Doing that made the change larger, as flags gets removed then restored.
> > > > > I had also thought the flag tests would get indented then unindented, but
> > > > > if we use guard() the indentation should remain unchanged.
> > > >
> > > > I'm fine with that as I pointed out (have you received that mail? I had
> > > > problems with my mail server) the dflags is better semantically, so restoration
> > > > with _different_ name is fine.
> > >
> > > I have noted that some of your replies have been delayed, and I can't be sure
> > > of what I might not've received. I can't say I've seen one that mentions the
> > > dflags name being preferable.
> > >
> > > I prefer the plain flags name, if there is only one flag variable in the
> > > function.
> > >
> > > > > Can do it in 1 if you are happy with the flags declaration being
> > > > > removed in patch 1 and restored in 4.
> > > >
> > > > Definitely.
> > >
> > > Ok will re-arrange in v3.
> >
> > Hang on - patch 4 has to use a scoped_guard(), so are you ok for patch 1
> > to introduce a guard(), to avoid changing the indentation, only to
> > replace it with a scoped_guard(), to perform the tests after releasing
> > the lock, in patch 4?
> 
> Alternatively, I can move patch 4 to the top of the series.

I'm fine as long as we do one thing in one patch (not spread over a few
as it seems feasible).
  
Kent Gibson Dec. 14, 2023, 4:05 p.m. UTC | #10
On Thu, Dec 14, 2023 at 05:50:16PM +0200, Andy Shevchenko wrote:
> On Thu, Dec 14, 2023 at 11:34:44PM +0800, Kent Gibson wrote:
> > On Thu, Dec 14, 2023 at 05:27:29PM +0200, Andy Shevchenko wrote:
> > > On Thu, Dec 14, 2023 at 11:19:01PM +0800, Kent Gibson wrote:
> > > > On Thu, Dec 14, 2023 at 05:10:23PM +0200, Andy Shevchenko wrote:
> > > > > On Thu, Dec 14, 2023 at 05:58:13PM +0800, Kent Gibson wrote:
>
> ...
>
> > > > > > -	spin_lock_irqsave(&gpio_lock, flags);
> > > > >
> > > > > Shouldn't this be covered by patch 1 (I mean conversion to scoped_guard()
> > > > > instead of spinlock)?
> > > >
> > > > Read the cover letter.
> > > > Doing that made the change larger, as flags gets removed then restored.
> > > > I had also thought the flag tests would get indented then unindented, but
> > > > if we use guard() the indentation should remain unchanged.
> > >
> > > I'm fine with that as I pointed out (have you received that mail? I had
> > > problems with my mail server) the dflags is better semantically, so restoration
> > > with _different_ name is fine.
> >
> > I have noted that some of your replies have been delayed, and I can't be sure
> > of what I might not've received. I can't say I've seen one that mentions the
> > dflags name being preferable.
> >
> > I prefer the plain flags name, if there is only one flag variable in the
> > function.
>
> I pointed out that lflags / dflags is kinda idiomatic internally to gpiolib*
> code base. Using flags might feel misleading and otherwise will hint about
> semantics of the variable. That said, I prefer it being named dflags.
>

Application of that idiom in gpiolib-cdev looks to be mixed, but I guess
it can't hurt to lean into it.

Cheers,
Kent.
  

Patch

diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index 7da3b3706547..73262305de0f 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -2378,74 +2378,72 @@  static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
 				  struct gpio_v2_line_info *info)
 {
 	struct gpio_chip *gc = desc->gdev->chip;
-	bool ok_for_pinctrl;
 	unsigned long flags;
 
 	memset(info, 0, sizeof(*info));
 	info->offset = gpio_chip_hwgpio(desc);
 
-	/*
-	 * This function takes a mutex so we must check this before taking
-	 * the spinlock.
-	 *
-	 * FIXME: find a non-racy way to retrieve this information. Maybe a
-	 * lock common to both frameworks?
-	 */
-	ok_for_pinctrl = pinctrl_gpio_can_use_line(gc, info->offset);
+	scoped_guard(spinlock_irqsave, &gpio_lock) {
+		if (desc->name)
+			strscpy(info->name, desc->name, sizeof(info->name));
 
-	spin_lock_irqsave(&gpio_lock, flags);
+		if (desc->label)
+			strscpy(info->consumer, desc->label,
+				sizeof(info->consumer));
 
-	if (desc->name)
-		strscpy(info->name, desc->name, sizeof(info->name));
-
-	if (desc->label)
-		strscpy(info->consumer, desc->label, sizeof(info->consumer));
+		flags = READ_ONCE(desc->flags);
+	}
 
 	/*
-	 * Userspace only need to know that the kernel is using this GPIO so
-	 * it can't use it.
+	 * Userspace only need know that the kernel is using this GPIO so it
+	 * can't use it.
+	 * The calculation of the used flag is slightly racy, as it may read
+	 * desc, gc and pinctrl state without a lock covering all three at
+	 * once.  Worst case if the line is in transition and the calculation
+	 * is inconsistent then it looks to the user like they performed the
+	 * read on the other side of the transition - but that can always
+	 * happen.
+	 * The definitive test that a line is available to userspace is to
+	 * request it.
 	 */
-	info->flags = 0;
-	if (test_bit(FLAG_REQUESTED, &desc->flags) ||
-	    test_bit(FLAG_IS_HOGGED, &desc->flags) ||
-	    test_bit(FLAG_USED_AS_IRQ, &desc->flags) ||
-	    test_bit(FLAG_EXPORT, &desc->flags) ||
-	    test_bit(FLAG_SYSFS, &desc->flags) ||
+	if (test_bit(FLAG_REQUESTED, &flags) ||
+	    test_bit(FLAG_IS_HOGGED, &flags) ||
+	    test_bit(FLAG_USED_AS_IRQ, &flags) ||
+	    test_bit(FLAG_EXPORT, &flags) ||
+	    test_bit(FLAG_SYSFS, &flags) ||
 	    !gpiochip_line_is_valid(gc, info->offset) ||
-	    !ok_for_pinctrl)
+	    !pinctrl_gpio_can_use_line(gc, info->offset))
 		info->flags |= GPIO_V2_LINE_FLAG_USED;
 
-	if (test_bit(FLAG_IS_OUT, &desc->flags))
+	if (test_bit(FLAG_IS_OUT, &flags))
 		info->flags |= GPIO_V2_LINE_FLAG_OUTPUT;
 	else
 		info->flags |= GPIO_V2_LINE_FLAG_INPUT;
 
-	if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
+	if (test_bit(FLAG_ACTIVE_LOW, &flags))
 		info->flags |= GPIO_V2_LINE_FLAG_ACTIVE_LOW;
 
-	if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
+	if (test_bit(FLAG_OPEN_DRAIN, &flags))
 		info->flags |= GPIO_V2_LINE_FLAG_OPEN_DRAIN;
-	if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
+	if (test_bit(FLAG_OPEN_SOURCE, &flags))
 		info->flags |= GPIO_V2_LINE_FLAG_OPEN_SOURCE;
 
-	if (test_bit(FLAG_BIAS_DISABLE, &desc->flags))
+	if (test_bit(FLAG_BIAS_DISABLE, &flags))
 		info->flags |= GPIO_V2_LINE_FLAG_BIAS_DISABLED;
-	if (test_bit(FLAG_PULL_DOWN, &desc->flags))
+	if (test_bit(FLAG_PULL_DOWN, &flags))
 		info->flags |= GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN;
-	if (test_bit(FLAG_PULL_UP, &desc->flags))
+	if (test_bit(FLAG_PULL_UP, &flags))
 		info->flags |= GPIO_V2_LINE_FLAG_BIAS_PULL_UP;
 
-	if (test_bit(FLAG_EDGE_RISING, &desc->flags))
+	if (test_bit(FLAG_EDGE_RISING, &flags))
 		info->flags |= GPIO_V2_LINE_FLAG_EDGE_RISING;
-	if (test_bit(FLAG_EDGE_FALLING, &desc->flags))
+	if (test_bit(FLAG_EDGE_FALLING, &flags))
 		info->flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING;
 
-	if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &desc->flags))
+	if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &flags))
 		info->flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME;
-	else if (test_bit(FLAG_EVENT_CLOCK_HTE, &desc->flags))
+	else if (test_bit(FLAG_EVENT_CLOCK_HTE, &flags))
 		info->flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE;
-
-	spin_unlock_irqrestore(&gpio_lock, flags);
 }
 
 struct gpio_chardev_data {