diff mbox series

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

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

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 Shevchenko 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 Shevchenko 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:46 p.m. UTC | #4
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 Shevchenko Dec. 14, 2023, 3:52 p.m. UTC | #5
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?
Andy Shevchenko Dec. 14, 2023, 4:02 p.m. UTC | #6
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).
diff mbox series

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 {