gpio: take the SRCU read lock in gpiod_hog()
authorBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Wed, 14 Feb 2024 08:44:16 +0000 (09:44 +0100)
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Thu, 15 Feb 2024 07:39:13 +0000 (08:39 +0100)
gpiod_hog() may be called without the gpio_device SRCU read lock taken
so we need to do it here as well. It's alright if someone else is
already holding the lock as SRCU read critical sections can be nested.

Fixes: d83cee3d2bb1 ("gpio: protect the pointer to gpio_chip in gpio_device with SRCU")
Reported-by: kernel test robot <oliver.sang@intel.com>
Closes: https://lore.kernel.org/oe-lkp/202402122234.d85cca9b-lkp@intel.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Paul E. McKenney <paulmck@kernel.org>
drivers/gpio/gpiolib.c

index f5434e559382e642584689db13d110c630e857fe..439d32d5aa380697a4c166ac077645f781c9e76f 100644 (file)
@@ -4492,24 +4492,27 @@ EXPORT_SYMBOL_GPL(gpiod_get_index_optional);
 int gpiod_hog(struct gpio_desc *desc, const char *name,
              unsigned long lflags, enum gpiod_flags dflags)
 {
-       struct gpio_chip *gc;
+       struct gpio_device *gdev = desc->gdev;
        struct gpio_desc *local_desc;
        int hwnum;
        int ret;
 
+       CLASS(gpio_chip_guard, guard)(desc);
+       if (!guard.gc)
+               return -ENODEV;
+
        if (test_and_set_bit(FLAG_IS_HOGGED, &desc->flags))
                return 0;
 
-       gc = gpiod_to_chip(desc);
        hwnum = gpio_chip_hwgpio(desc);
 
-       local_desc = gpiochip_request_own_desc(gc, hwnum, name,
+       local_desc = gpiochip_request_own_desc(guard.gc, hwnum, name,
                                               lflags, dflags);
        if (IS_ERR(local_desc)) {
                clear_bit(FLAG_IS_HOGGED, &desc->flags);
                ret = PTR_ERR(local_desc);
                pr_err("requesting hog GPIO %s (chip %s, offset %d) failed, %d\n",
-                      name, gc->label, hwnum, ret);
+                      name, gdev->label, hwnum, ret);
                return ret;
        }