mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Armin Wolf <W_Armin@gmx.de>
To: lee@kernel.org, pavel@kernel.org
Cc: linux-leds@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 04/10] leds: class: Create "brightness_hw_changed" attribute atomically
Date: Sun, 18 Oct 2026 15:46:23 +0200	[thread overview]
Message-ID: <20261018135339.1109271-5-W_Armin@gmx.de> (raw)
In-Reply-To: <20261018135339.1109271-1-W_Armin@gmx.de>

Using device_create_file() might cause userspace applications
listening for uevents to inspect a new LED device before the kernel
has registered all sysfs attributes for it. This might cause those
applications to incorrectly assume that the new LED device does not
support the "brightness_hw_changed" attribute.

Fix this by letting the device core create the sysfs attribute before
the uevent is being send to userspace.

Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
 drivers/leds/led-class.c | 85 +++++++++++++++-------------------------
 include/linux/leds.h     |  2 -
 2 files changed, 31 insertions(+), 56 deletions(-)

diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 3775ad13762f..d460f041ed86 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -17,6 +17,7 @@
 #include <linux/property.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/sysfs.h>
 #include <linux/timer.h>
 #include <uapi/linux/uleds.h>
 #include <linux/of.h>
@@ -101,14 +102,6 @@ static const struct attribute_group led_group = {
 	.attrs_const = led_class_attrs,
 };
 
-static const struct attribute_group *const led_groups[] = {
-	&led_group,
-#ifdef CONFIG_LEDS_TRIGGERS
-	&led_trigger_group,
-#endif
-	NULL,
-};
-
 #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
 static ssize_t brightness_hw_changed_show(struct device *dev, const struct device_attribute *attr,
 					  char *buf)
@@ -123,51 +116,48 @@ static ssize_t brightness_hw_changed_show(struct device *dev, const struct devic
 
 static const DEVICE_ATTR_RO(brightness_hw_changed);
 
-static int led_add_brightness_hw_changed(struct led_classdev *led_cdev)
-{
-	struct device *dev = led_cdev->dev;
-	int ret;
+static const struct attribute *const led_brightness_hw_changed_attrs[] = {
+	&dev_attr_brightness_hw_changed.attr,
+	NULL,
+};
 
-	ret = device_create_file(dev, &dev_attr_brightness_hw_changed);
-	if (ret) {
-		dev_err(dev, "Error creating brightness_hw_changed\n");
-		return ret;
-	}
+static umode_t led_brightness_hw_changed_is_visible(struct kobject *kobj,
+						    const struct attribute *attr, int n)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 
-	led_cdev->brightness_hw_changed_kn =
-		sysfs_get_dirent(dev->kobj.sd, "brightness_hw_changed");
-	if (!led_cdev->brightness_hw_changed_kn) {
-		dev_err(dev, "Error getting brightness_hw_changed kn\n");
-		device_remove_file(dev, &dev_attr_brightness_hw_changed);
-		return -ENXIO;
-	}
+	if (attr == &dev_attr_brightness_hw_changed.attr &&
+	    led_cdev->flags & LED_BRIGHT_HW_CHANGED)
+		return attr->mode;
 
 	return 0;
 }
 
-static void led_remove_brightness_hw_changed(struct led_classdev *led_cdev)
-{
-	sysfs_put(led_cdev->brightness_hw_changed_kn);
-	device_remove_file(led_cdev->dev, &dev_attr_brightness_hw_changed);
-}
+static const struct attribute_group led_brightness_hw_changed_group = {
+	.is_visible_const = led_brightness_hw_changed_is_visible,
+	.attrs_const = led_brightness_hw_changed_attrs,
+};
+#endif	/* CONFIG_LEDS_BRIGHTNESS_HW_CHANGED */
 
+static const struct attribute_group *const led_groups[] = {
+	&led_group,
+#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
+	&led_brightness_hw_changed_group,
+#endif
+#ifdef CONFIG_LEDS_TRIGGERS
+	&led_trigger_group,
+#endif
+	NULL,
+};
+
+#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
 void led_classdev_notify_brightness_hw_changed(struct led_classdev *led_cdev, unsigned int brightness)
 {
-	if (WARN_ON(!led_cdev->brightness_hw_changed_kn))
-		return;
-
 	led_cdev->brightness_hw_changed = brightness;
-	sysfs_notify_dirent(led_cdev->brightness_hw_changed_kn);
+	sysfs_notify(&led_cdev->dev->kobj, NULL, "brightness_hw_changed");
 }
 EXPORT_SYMBOL_GPL(led_classdev_notify_brightness_hw_changed);
-#else
-static int led_add_brightness_hw_changed(struct led_classdev *led_cdev)
-{
-	return 0;
-}
-static void led_remove_brightness_hw_changed(struct led_classdev *led_cdev)
-{
-}
 #endif
 
 /**
@@ -544,16 +534,6 @@ int led_classdev_register_ext(struct device *parent,
 	if (init_data && init_data->fwnode)
 		device_set_node(led_cdev->dev, init_data->fwnode);
 
-	if (led_cdev->flags & LED_BRIGHT_HW_CHANGED) {
-		ret = led_add_brightness_hw_changed(led_cdev);
-		if (ret) {
-			device_unregister(led_cdev->dev);
-			led_cdev->dev = NULL;
-			mutex_unlock(&led_cdev->led_access);
-			return ret;
-		}
-	}
-
 	led_cdev->work_flags = 0;
 #ifdef CONFIG_LEDS_TRIGGERS
 	init_rwsem(&led_cdev->trigger_lock);
@@ -626,9 +606,6 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
 
 	flush_work(&led_cdev->set_brightness_work);
 
-	if (led_cdev->flags & LED_BRIGHT_HW_CHANGED)
-		led_remove_brightness_hw_changed(led_cdev);
-
 	device_unregister(led_cdev->dev);
 
 	down_write(&leds_list_lock);
diff --git a/include/linux/leds.h b/include/linux/leds.h
index beaf23993063..6f975078cc14 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -21,7 +21,6 @@ struct attribute_group;
 struct device_node;
 struct fwnode_handle;
 struct gpio_desc;
-struct kernfs_node;
 struct led_pattern;
 struct platform_device;
 
@@ -237,7 +236,6 @@ struct led_classdev {
 
 #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
 	int			 brightness_hw_changed;
-	struct kernfs_node	*brightness_hw_changed_kn;
 #endif
 
 #ifdef CONFIG_LEDS_TRIGGERS_HW_CHANGED
-- 
2.56.0


  parent reply	other threads:[~2026-10-18 13:54 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-18 13:46 [PATCH 00/10] leds: class: Support custom sysfs groups on multicolor and flash LEDs Armin Wolf
2026-10-18 13:46 ` [PATCH 01/10] leds: class: Constify sysfs attributes Armin Wolf
2026-10-18 13:46 ` [PATCH 02/10] leds: multicolor: " Armin Wolf
2026-10-18 13:46 ` [PATCH 03/10] leds: flash: " Armin Wolf
2026-10-18 13:46 ` Armin Wolf [this message]
2026-10-19 11:51   ` [PATCH 04/10] leds: class: Create "brightness_hw_changed" attribute atomically Rong Zhang
2026-10-20 20:55     ` Armin Wolf
2026-10-18 13:46 ` [PATCH 05/10] leds: class: Fix race condition when creating the device Armin Wolf
2026-10-18 13:46 ` [PATCH 06/10] leds: class: Take the LED access lock when reading brightness_hw_changed Armin Wolf
2026-10-18 13:46 ` [PATCH 07/10] leds: class: Use correct type for brightness_hw_changed field Armin Wolf
2026-10-18 13:46 ` [PATCH 08/10] leds: class: Split led_classdev_register_ext() Armin Wolf
2026-10-18 13:46 ` [PATCH 09/10] leds: Support custom sysfs groups on multicolor and flash LEDs Armin Wolf
2026-10-19 11:53   ` Rong Zhang
2026-10-20 20:57     ` Armin Wolf
2026-10-18 13:46 ` [PATCH 10/10] leds: multicolor: Adjust maximum subled intensity during initialization Armin Wolf
2026-10-19 11:54   ` Rong Zhang
2026-10-20 20:59     ` Armin Wolf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261018135339.1109271-5-W_Armin@gmx.de \
    --to=w_armin@gmx.de \
    --cc=lee@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-leds@vger.kernel.org \
    --cc=pavel@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®