On Mon, Feb 05, 2024 at 10:34:16AM +0100, Bartosz Golaszewski wrote: > From: Bartosz Golaszewski <bartosz.golaszewski@xxxxxxxxxx> > > 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. ... > static ssize_t base_show(struct device *dev, > struct device_attribute *attr, char *buf) > { > - const struct gpio_device *gdev = dev_get_drvdata(dev); > + struct gpio_device *gdev = dev_get_drvdata(dev); > + struct gpio_chip *gc; > > - return sysfs_emit(buf, "%d\n", gdev->chip->base); > + guard(srcu)(&gdev->srcu); > + > + gc = rcu_dereference(gdev->chip); > + if (!gc) > + return -ENODEV; > + > + return sysfs_emit(buf, "%d\n", gc->base); Similar Q as below. > } ... > static ssize_t label_show(struct device *dev, > struct device_attribute *attr, char *buf) > { > - const struct gpio_device *gdev = dev_get_drvdata(dev); > + struct gpio_device *gdev = dev_get_drvdata(dev); > + struct gpio_chip *gc; > > - return sysfs_emit(buf, "%s\n", gdev->chip->label ?: ""); > + guard(srcu)(&gdev->srcu); > + > + gc = rcu_dereference(gdev->chip); > + if (!gc) > + return -ENODEV; > + > + return sysfs_emit(buf, "%s\n", gc->label ?: ""); Why do you need gc label here and not gdev? In other code you switched over (in a patch before this in the series). > } > static ssize_t ngpio_show(struct device *dev, > struct device_attribute *attr, char *buf) > { > - const struct gpio_device *gdev = dev_get_drvdata(dev); > + struct gpio_device *gdev = dev_get_drvdata(dev); > + struct gpio_chip *gc; > > - return sysfs_emit(buf, "%u\n", gdev->chip->ngpio); > + guard(srcu)(&gdev->srcu); > + > + gc = rcu_dereference(gdev->chip); > + if (!gc) > + return -ENODEV; > + > + return sysfs_emit(buf, "%u\n", gc->ngpio); Ditto. > } ... > int gpiod_get_direction(struct gpio_desc *desc) > { > - struct gpio_chip *gc; > unsigned long flags; > unsigned int offset; > int ret; > > - gc = gpiod_to_chip(desc); > + if (!desc) > + /* Sane default is INPUT. */ > + return 1; Hmm... I can't imagine how this value may anyhow be used / useful. > + if (IS_ERR(desc)) > + return -EINVAL; With above said, can't we use one of VALIDATE_DESC*() macro here? ... > list_for_each_entry_srcu(gdev, &gpio_devices, list, > srcu_read_lock_held(&gpio_devices_srcu)) { > + list_for_each_entry_srcu(gdev, &gpio_devices, list, > + srcu_read_lock_held(&gpio_devices_srcu)) { Seems like a candidate for #define gpio_for_each_device(...) ... ... > VALIDATE_DESC(desc); > > - gc = desc->gdev->chip; > - if (!gc->en_hw_timestamp) { > + CLASS(gpio_chip_guard, guard)(desc); > + if (!guard.gc) > + return -ENODEV; Not sure if it would be good to have a respective VALIDATE_DESC_GUARDED() or so. At least it may deduplicate a few cases. ... > + /* FIXME Cannot use gpio_chip_guard due to const desc. */ gpio_chip_guard() -- With Best Regards, Andy Shevchenko