On Fri, Mar 31, 2023 at 11:33 AM Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> wrote: > > Some classes (i.e. gpio), want to know if they have been registered or > not, and poke around in the class's internal structures to try to figure > this out. Because this is not really a good idea, provide a function > for classes to call to try to figure this out. > > Note, this is racy as the state of the class could change at any moment > in time after the call is made, but as usually a class only wants to > know if it has been registered yet or not, it should be fairly safe to > use, and is just as safe as the previous "poke at the class internals" > check was. > > Move the gpiolib code to use this function as proof that it works > properly. > > Cc: Linus Walleij <linus.walleij@xxxxxxxxxx> > Cc: Bartosz Golaszewski <brgl@xxxxxxxx> > Cc: Sebastian Reichel <sre@xxxxxxxxxx> > Cc: Benjamin Tissoires <benjamin.tissoires@xxxxxxxxxx> > Cc: linux-gpio@xxxxxxxxxxxxxxx > Cc: "Rafael J. Wysocki" <rafael@xxxxxxxxxx> > Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> Reviewed-by: Rafael J. Wysocki <rafael@xxxxxxxxxx> > --- > drivers/base/class.c | 25 +++++++++++++++++++++++++ > drivers/gpio/gpiolib-sysfs.c | 4 ++-- > include/linux/device/class.h | 1 + > 3 files changed, 28 insertions(+), 2 deletions(-) > > diff --git a/drivers/base/class.c b/drivers/base/class.c > index 68a6f9b56d19..a8a1bf976290 100644 > --- a/drivers/base/class.c > +++ b/drivers/base/class.c > @@ -634,6 +634,31 @@ void class_compat_remove_link(struct class_compat *cls, struct device *dev, > } > EXPORT_SYMBOL_GPL(class_compat_remove_link); > > +/** > + * class_is_registered - determine if at this moment in time, a class is > + * registered in the driver core or not. > + * @class: the class to check > + * > + * Returns a boolean to state if the class is registered in the driver core > + * or not. Note that the value could switch right after this call is made, > + * so only use this in places where you "know" it is safe to do so (usually > + * to determine if the specific class has been registered yet or not). > + * > + * Be careful in using this. > + */ > +bool class_is_registered(const struct class *class) > +{ > + struct subsys_private *sp = class_to_subsys(class); > + bool is_initialized = false; > + > + if (sp) { > + is_initialized = true; > + subsys_put(sp); > + } > + return is_initialized; > +} > +EXPORT_SYMBOL_GPL(class_is_registered); > + > int __init classes_init(void) > { > class_kset = kset_create_and_add("class", NULL, NULL); > diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c > index a895915affa5..1a9b21731cc9 100644 > --- a/drivers/gpio/gpiolib-sysfs.c > +++ b/drivers/gpio/gpiolib-sysfs.c > @@ -554,7 +554,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) > int offset; > > /* can't export until sysfs is available ... */ > - if (!gpio_class.p) { > + if (!class_is_registered(&gpio_class)) { > pr_debug("%s: called too early!\n", __func__); > return -ENOENT; > } > @@ -728,7 +728,7 @@ int gpiochip_sysfs_register(struct gpio_device *gdev) > * register later, in gpiolib_sysfs_init() ... here we just > * verify that _some_ field of gpio_class got initialized. > */ > - if (!gpio_class.p) > + if (!class_is_registered(&gpio_class)) > return 0; > > /* > diff --git a/include/linux/device/class.h b/include/linux/device/class.h > index b53728ca56fb..9cb5db0588c8 100644 > --- a/include/linux/device/class.h > +++ b/include/linux/device/class.h > @@ -84,6 +84,7 @@ extern struct kobject *sysfs_dev_block_kobj; > > int __must_check class_register(struct class *class); > void class_unregister(const struct class *class); > +bool class_is_registered(const struct class *class); > > struct class_compat; > struct class_compat *class_compat_register(const char *name); > -- > 2.40.0 >