diff mbox series

[2/7] driver core: create class_is_registered()

Message ID 20230331093318.82288-2-gregkh@linuxfoundation.org
State New
Headers show
Series None | expand

Commit Message

gregkh@linuxfoundation.org March 31, 2023, 9:33 a.m. UTC
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@linaro.org>
Cc: Bartosz Golaszewski <brgl@bgdev.pl>
Cc: Sebastian Reichel <sre@kernel.org>
Cc: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Cc: linux-gpio@vger.kernel.org
Cc: "Rafael J. Wysocki" <rafael@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/base/class.c         | 25 +++++++++++++++++++++++++
 drivers/gpio/gpiolib-sysfs.c |  4 ++--
 include/linux/device/class.h |  1 +
 3 files changed, 28 insertions(+), 2 deletions(-)

Comments

Rafael J. Wysocki March 31, 2023, 10:16 a.m. UTC | #1
On Fri, Mar 31, 2023 at 11:33 AM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> 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@linaro.org>
> Cc: Bartosz Golaszewski <brgl@bgdev.pl>
> Cc: Sebastian Reichel <sre@kernel.org>
> Cc: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> Cc: linux-gpio@vger.kernel.org
> Cc: "Rafael J. Wysocki" <rafael@kernel.org>
> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Reviewed-by: Rafael J. Wysocki <rafael@kernel.org>

> ---
>  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
>
Linus Walleij March 31, 2023, 12:44 p.m. UTC | #2
On Fri, Mar 31, 2023 at 11:33 AM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> 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@linaro.org>
> Cc: Bartosz Golaszewski <brgl@bgdev.pl>
> Cc: Sebastian Reichel <sre@kernel.org>
> Cc: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> Cc: linux-gpio@vger.kernel.org
> Cc: "Rafael J. Wysocki" <rafael@kernel.org>
> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

This looks good to me!
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij
diff mbox series

Patch

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);