]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
driver core: faux: Add sysfs groups after probing
authorKurt Borja <kuurtb@gmail.com>
Thu, 27 Mar 2025 23:19:37 +0000 (20:19 -0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 15 Apr 2025 12:16:08 +0000 (14:16 +0200)
Manually add sysfs groups after the faux_device_ops's probe succeeds.
Likewise remove these groups just before calling the faux_devices_ops's
remove callback. This approach approximates the order in which the
driver core adds and removes the driver's .dev_groups of a device to
avoid lifetime issues.

This is done specifically to avoid using the device's .groups member,
which adds groups before the device is even registered to the bus.

This lets consumers of this API, initialize resources on the .probe
callback and then use them inside is_visible/show/store methods, through
dev_get_drvdata() without races.

Cc: Rafael J. Wysocki <rafael@kernel.org>
Cc: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
Link: https://lore.kernel.org/r/20250327-faux-groups-v2-1-745a3cf0bc16@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/base/faux.c

index 407c1d1aad50b7969a6dab9d2027d8beab66a754..9054d346bd7fe89575b95c1491467850bcd0393a 100644 (file)
@@ -25,6 +25,7 @@
 struct faux_object {
        struct faux_device faux_dev;
        const struct faux_device_ops *faux_ops;
+       const struct attribute_group **groups;
 };
 #define to_faux_object(dev) container_of_const(dev, struct faux_object, faux_dev.dev)
 
@@ -43,10 +44,21 @@ static int faux_probe(struct device *dev)
        struct faux_object *faux_obj = to_faux_object(dev);
        struct faux_device *faux_dev = &faux_obj->faux_dev;
        const struct faux_device_ops *faux_ops = faux_obj->faux_ops;
-       int ret = 0;
+       int ret;
 
-       if (faux_ops && faux_ops->probe)
+       if (faux_ops && faux_ops->probe) {
                ret = faux_ops->probe(faux_dev);
+               if (ret)
+                       return ret;
+       }
+
+       /*
+        * Add groups after the probe succeeds to ensure resources are
+        * initialized correctly
+        */
+       ret = device_add_groups(dev, faux_obj->groups);
+       if (ret && faux_ops && faux_ops->remove)
+               faux_ops->remove(faux_dev);
 
        return ret;
 }
@@ -57,6 +69,8 @@ static void faux_remove(struct device *dev)
        struct faux_device *faux_dev = &faux_obj->faux_dev;
        const struct faux_device_ops *faux_ops = faux_obj->faux_ops;
 
+       device_remove_groups(dev, faux_obj->groups);
+
        if (faux_ops && faux_ops->remove)
                faux_ops->remove(faux_dev);
 }
@@ -124,8 +138,9 @@ struct faux_device *faux_device_create_with_groups(const char *name,
        if (!faux_obj)
                return NULL;
 
-       /* Save off the callbacks so we can use them in the future */
+       /* Save off the callbacks and groups so we can use them in the future */
        faux_obj->faux_ops = faux_ops;
+       faux_obj->groups = groups;
 
        /* Initialize the device portion and register it with the driver core */
        faux_dev = &faux_obj->faux_dev;
@@ -138,7 +153,6 @@ struct faux_device *faux_device_create_with_groups(const char *name,
        else
                dev->parent = &faux_bus_root;
        dev->bus = &faux_bus_type;
-       dev->groups = groups;
        dev_set_name(dev, "%s", name);
 
        ret = device_add(dev);