diff options
author | Bartosz Golaszewski <bartosz.golaszewski@linaro.org> | 2024-01-23 12:01:10 +0100 |
---|---|---|
committer | Bartosz Golaszewski <bartosz.golaszewski@linaro.org> | 2024-02-12 11:00:31 +0100 |
commit | d83cee3d2bb131c7fca7e19f1e33dc7530fd7083 (patch) | |
tree | dc59f13db90d3fa22c44d0348534bedadc3dce33 /drivers/gpio/gpiolib.h | |
parent | gpio: add SRCU infrastructure to struct gpio_device (diff) | |
download | linux-d83cee3d2bb131c7fca7e19f1e33dc7530fd7083.tar.xz linux-d83cee3d2bb131c7fca7e19f1e33dc7530fd7083.zip |
gpio: protect the pointer to gpio_chip in gpio_device with SRCU
Ensure we cannot crash if the GPIO device gets unregistered (and the
chip pointer set to NULL) during any of the API calls.
To that end: wait for all users of gdev->chip to exit their read-only
SRCU critical sections in gpiochip_remove().
For brevity: add a guard class which can be instantiated at the top of
every function requiring read-only access to the chip pointer and use it
in all API calls taking a GPIO descriptor as argument. In places where
we only deal with the GPIO device - use regular guard() helpers and
rcu_dereference() for chip access. Do the same in API calls taking a
const pointer to gpio_desc.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Diffstat (limited to '')
-rw-r--r-- | drivers/gpio/gpiolib.h | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 35d71e30c546..b3810f7d286a 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -63,7 +63,7 @@ struct gpio_device { int id; struct device *mockdev; struct module *owner; - struct gpio_chip *chip; + struct gpio_chip __rcu *chip; struct gpio_desc *descs; int base; u16 ngpio; @@ -193,6 +193,26 @@ struct gpio_desc { #define gpiod_not_found(desc) (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT) +struct gpio_chip_guard { + struct gpio_device *gdev; + struct gpio_chip *gc; + int idx; +}; + +DEFINE_CLASS(gpio_chip_guard, + struct gpio_chip_guard, + srcu_read_unlock(&_T.gdev->srcu, _T.idx), + ({ + struct gpio_chip_guard _guard; + + _guard.gdev = desc->gdev; + _guard.idx = srcu_read_lock(&_guard.gdev->srcu); + _guard.gc = rcu_dereference(_guard.gdev->chip); + + _guard; + }), + struct gpio_desc *desc) + int gpiod_request(struct gpio_desc *desc, const char *label); void gpiod_free(struct gpio_desc *desc); |