diff options
author | Bartosz Golaszewski <bgolaszewski@baylibre.com> | 2020-04-17 09:01:51 +0200 |
---|---|---|
committer | Bartosz Golaszewski <bgolaszewski@baylibre.com> | 2020-04-23 17:55:27 +0200 |
commit | 6409d049ce28bef35e13dfb8699fc7ee27469ba1 (patch) | |
tree | 4d5fc17f31d6c8e1906f7534260169a8936e8354 /drivers/gpio | |
parent | 4e1541593017d76cfa04bd666de8e4dbcfe3105d (diff) | |
download | linux-6409d049ce28bef35e13dfb8699fc7ee27469ba1.tar.gz linux-6409d049ce28bef35e13dfb8699fc7ee27469ba1.tar.bz2 linux-6409d049ce28bef35e13dfb8699fc7ee27469ba1.zip |
gpiolib: don't call sleeping functions with a spinlock taken
We must not call pinctrl_gpio_can_use_line() with the gpio_lock taken
as it takes a mutex internally. Let's move the call before taking the
spinlock and store the return value.
This isn't perfect - there's a moment between calling
pinctrl_gpio_can_use_line() and taking the spinlock where the situation
can change but it isn't a regression either: previously this part wasn't
protected at all and it only affects the information user-space is
seeing.
Reported-by: Geert Uytterhoeven <geert@linux-m68k.org>
Fixes: d2ac25798208 ("gpiolib: provide a dedicated function for setting lineinfo")
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/gpiolib.c | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 29f6abe84d2e..bf9732ab7f91 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1158,8 +1158,19 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc, struct gpioline_info *info) { struct gpio_chip *gc = desc->gdev->chip; + bool ok_for_pinctrl; unsigned long flags; + /* + * 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->base + info->line_offset); + spin_lock_irqsave(&gpio_lock, flags); if (desc->name) { @@ -1186,7 +1197,7 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc, test_bit(FLAG_USED_AS_IRQ, &desc->flags) || test_bit(FLAG_EXPORT, &desc->flags) || test_bit(FLAG_SYSFS, &desc->flags) || - !pinctrl_gpio_can_use_line(gc->base + info->line_offset)) + !ok_for_pinctrl) info->flags |= GPIOLINE_FLAG_KERNEL; if (test_bit(FLAG_IS_OUT, &desc->flags)) info->flags |= GPIOLINE_FLAG_IS_OUT; |