From: sashiko-bot@kernel.org
To: "Armin Wolf" <W_Armin@gmx.de>
Cc: linux-leds@vger.kernel.org, lee@kernel.org
Subject: Re: [PATCH 04/10] leds: class: Create "brightness_hw_changed" attribute atomically
Date: Sun, 18 Oct 2026 14:11:18 +0000 [thread overview]
Message-ID: <sashiko-outbox-176187@kernel.org> (raw)
In-Reply-To: <20261018135339.1109271-5-W_Armin@gmx.de>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] leds: class: sleeping in atomic context in led_classdev_notify_brightness_hw_changed()
- [High] leds: NULL or ERR_PTR dereference in led_classdev_notify_brightness_hw_changed()
--
commit a70a68ffb21d71853f220e24fa090cea4db91df2
Author: Armin Wolf <W_Armin@gmx.de>
leds: class: Create "brightness_hw_changed" attribute atomically
This patch converts the brightness_hw_changed sysfs attribute to a static
attribute group with an is_visible callback so that the device core creates
it before sending the uevent to userspace. It also removes the cached
kernfs_node pointer from struct led_classdev and switches
led_classdev_notify_brightness_hw_changed() to use sysfs_notify().
> diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
> index 3775ad13762f5..d460f041ed86e 100644
> --- a/drivers/leds/led-class.c
> +++ b/drivers/leds/led-class.c
[ ... ]
> @@ -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,
> +};
[ ... ]
> +#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);
[Severity: High]
Can replacing sysfs_notify_dirent() with sysfs_notify() here cause sleeping
in atomic context?
Previously, sysfs_notify_dirent() called kernfs_notify() on the cached
kernfs_node, which may be called from any context since it only uses
rcu_read_lock(), spin_lock_irqsave(&kernfs_notify_lock, flags), and
schedule_work().
With sysfs_notify(&led_cdev->dev->kobj, NULL, "brightness_hw_changed"), a
non-NULL attribute name causes sysfs_notify() to look up the node via
kernfs_find_and_get() -> kernfs_find_and_get_ns(), which acquires the
sleeping rw_semaphore root->kernfs_rwsem:
fs/sysfs/file.c:sysfs_notify() {
...
if (kn && attr) {
tmp = kernfs_find_and_get(kn, attr);
kernfs_put(kn);
kn = tmp;
}
...
}
fs/kernfs/dir.c:kernfs_find_and_get_ns() {
...
down_read(&root->kernfs_rwsem);
kn = kernfs_find_ns(parent, name, ns);
kernfs_get(kn);
up_read(&root->kernfs_rwsem);
...
}
In drivers/hid/hid-lg-g15.c, lg_g13_event() and lg_g510_leds_event() call
led_classdev_notify_brightness_hw_changed() when a hardware backlight
brightness change report arrives:
drivers/hid/hid-lg-g15.c:lg_g13_event() {
...
if (backlight_disabled ^ g15->backlight_disabled) {
led_classdev_notify_brightness_hw_changed(
&g15->leds[LG_G15_KBD_BRIGHTNESS].mcdev.led_cdev,
backlight_disabled
? 0 : g15->leds[LG_G15_KBD_BRIGHTNESS].brightness);
g15->backlight_disabled = backlight_disabled;
}
...
}
Those handlers are invoked from lg_g15_raw_event() via the USB interrupt URB
completion path hid_irq_in() -> hid_safe_input_report() ->
__hid_input_report(), which runs in hardirq/atomic context.
[Severity: High]
Also in led_classdev_notify_brightness_hw_changed(), could removing the
WARN_ON(!led_cdev->brightness_hw_changed_kn) guard lead to a NULL or ERR_PTR
dereference on led_cdev->dev (or a use-after-free after commit "leds: class:
Split led_classdev_register_ext()" later in the series)?
Previously, if a classdev was not registered or did not set
LED_BRIGHT_HW_CHANGED, led_cdev->brightness_hw_changed_kn was NULL and the
function warned and returned before touching led_cdev->dev. That behavior is
also documented in Documentation/leds/leds-class.rst:
Calling led_classdev_notify_brightness_hw_changed on a classdev not
registered with the LED_BRIGHT_HW_CHANGED flag is a bug and will
trigger a WARN_ON.
Without a guard, sysfs_notify(&led_cdev->dev->kobj, ...) immediately
dereferences kobj->sd in fs/sysfs/file.c:sysfs_notify().
For example, in drivers/platform/x86/system76_acpi.c, system76_probe() skips
registering data->kb_led when data->kbled_type == KBLED_NONE, leaving
data->kb_led.dev as NULL:
drivers/platform/x86/system76_acpi.c:system76_probe() {
...
if (data->kbled_type != KBLED_NONE) {
err = devm_led_classdev_register(&pdev->dev, &data->kb_led);
if (err)
return err;
}
...
}
However, system76_notify() is still installed and calls kb_led_notify() ->
led_classdev_notify_brightness_hw_changed(&data->kb_led, ...) through
kb_led_hotkey_hardware(), kb_led_hotkey_toggle(), kb_led_hotkey_down(), and
kb_led_hotkey_up() on ACPI events 0x80-0x83.
Similarly, in drivers/platform/x86/toshiba_acpi.c, toshiba_acpi_probe()
ignores the return value of led_classdev_register(&pdev->dev, &dev->kbd_led):
drivers/platform/x86/toshiba_acpi.c:toshiba_acpi_probe() {
...
if (dev->kbd_illum_supported &&
(dev->kbd_mode == SCI_KBD_MODE_FNZ || dev->kbd_type == 2)) {
dev->kbd_led.name = "toshiba::kbd_backlight";
dev->kbd_led.flags = LED_BRIGHT_HW_CHANGED;
dev->kbd_led.max_brightness = 1;
dev->kbd_led.brightness_set = toshiba_kbd_backlight_set;
dev->kbd_led.brightness_get = toshiba_kbd_backlight_get;
led_classdev_register(&pdev->dev, &dev->kbd_led);
}
...
}
If registration fails, dev->kbd_led.dev is left as NULL or ERR_PTR (or a
freed pointer after "leds: class: Split led_classdev_register_ext()"), while
toshiba_acpi_notify() and toshiba_acpi_kbd_bl_work() still call
led_classdev_notify_brightness_hw_changed(&dev->kbd_led, ...).
> -#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
[ ... ]
>
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261018135339.1109271-1-W_Armin@gmx.de?part=4
next prev parent reply other threads:[~2026-10-18 14:11 UTC|newest]
Thread overview: 23+ 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:57 ` sashiko-bot
2026-10-18 13:46 ` [PATCH 02/10] leds: multicolor: " Armin Wolf
2026-10-18 13:57 ` sashiko-bot
2026-10-18 13:46 ` [PATCH 03/10] leds: flash: " Armin Wolf
2026-10-18 13:56 ` sashiko-bot
2026-10-18 13:46 ` [PATCH 04/10] leds: class: Create "brightness_hw_changed" attribute atomically Armin Wolf
2026-10-18 14:11 ` sashiko-bot [this message]
2026-10-18 13:46 ` [PATCH 05/10] leds: class: Fix race condition when creating the device Armin Wolf
2026-10-18 13:58 ` sashiko-bot
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 14:03 ` sashiko-bot
2026-10-18 17:08 ` 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 14:11 ` sashiko-bot
2026-10-18 13:46 ` [PATCH 08/10] leds: class: Split led_classdev_register_ext() Armin Wolf
2026-10-18 14:15 ` sashiko-bot
2026-10-18 17:14 ` Armin Wolf
2026-10-18 13:46 ` [PATCH 09/10] leds: Support custom sysfs groups on multicolor and flash LEDs Armin Wolf
2026-10-18 14:09 ` sashiko-bot
2026-10-18 13:46 ` [PATCH 10/10] leds: multicolor: Adjust maximum subled intensity during initialization Armin Wolf
2026-10-18 13:58 ` sashiko-bot
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=sashiko-outbox-176187@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=W_Armin@gmx.de \
--cc=lee@kernel.org \
--cc=linux-leds@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.