From: "Sverdlin, Alexander" <alexander.sverdlin@siemens.com>
To: "sashiko-reviews@lists.linux.dev"
<sashiko-reviews@lists.linux.dev>,
"linux-leds@vger.kernel.org" <linux-leds@vger.kernel.org>
Cc: "lee@kernel.org" <lee@kernel.org>
Subject: Re: [PATCH v5 4/4] leds: trigger: netdev: Serialize mode/interval stores with trigger lock
Date: Tue, 20 Oct 2026 14:40:48 +0000 [thread overview]
Message-ID: <bcabe7eaf6efdf59b7378fed3533ccc2d44382b1.camel@siemens.com> (raw)
In-Reply-To: <sashiko-outbox-178980@kernel.org>
Hi all,
On Tue, 2026-10-20 at 12:59 +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [Medium] leds: trigger: netdev: unlocked hw_control check in interval_store()
> - [Medium] leds: trigger: netdev: missing carrier_link_up check in netdev_trig_sw_blink()
ACK, both findings will be fixed in v6.
> --
>
> commit fa618832fa8e967d013f87c080cded7d0b155827
> Author: Alexander Sverdlin <alexander.sverdlin@siemens.com>
>
> leds: trigger: netdev: Serialize mode/interval stores with trigger lock
>
> This commit serializes sysfs mode and interval attribute stores in the
> netdev LED trigger using trigger_data->lock, switches to asynchronous
> work cancellation to avoid deadlocking with netdev_trig_work(), and adds
> a netdev_trig_sw_blink() helper to gate software activity polling.
>
> > diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
> > index bf9a5ec245a43..6859783422f5d 100644
> > --- a/drivers/leds/trigger/ledtrig-netdev.c
> > +++ b/drivers/leds/trigger/ledtrig-netdev.c
> > @@ -81,6 +81,16 @@ struct led_netdev_data {
> >
> > static const struct attribute_group netdev_trig_link_speed_attrs_group;
> >
> > +/* True while the software activity worker should keep polling and blinking. */
> > +static bool netdev_trig_sw_blink(struct led_netdev_data *trigger_data)
> > +{
> > + return trigger_data->net_dev && !trigger_data->hw_control &&
> > + (test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) ||
> > + test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode) ||
> > + test_bit(TRIGGER_NETDEV_TX_ERR, &trigger_data->mode) ||
> > + test_bit(TRIGGER_NETDEV_RX_ERR, &trigger_data->mode));
> > +}
>
> [Severity: Medium]
> Should netdev_trig_sw_blink() also check trigger_data->carrier_link_up?
>
> In set_baseline_state(), trigger_data->work is only scheduled when
> trigger_data->carrier_link_up is true, and it is not cancelled when
> carrier_link_up is false:
>
> drivers/leds/trigger/ledtrig-netdev.c:set_baseline_state() {
> if (!trigger_data->carrier_link_up) {
> led_set_brightness(led_cdev, LED_OFF);
> } else {
> ...
> if (netdev_trig_sw_blink(trigger_data))
> schedule_delayed_work(&trigger_data->work, 0);
> }
> }
>
> Both netdev_trig_notify() and set_device_name() call
> cancel_delayed_work_sync(&trigger_data->work) before acquiring
> trigger_data->lock:
>
> drivers/leds/trigger/ledtrig-netdev.c:netdev_trig_notify() {
> cancel_delayed_work_sync(&trigger_data->work);
>
> mutex_lock(&trigger_data->lock);
>
> trigger_data->carrier_link_up = false;
> ...
> set_baseline_state(trigger_data);
>
> mutex_unlock(&trigger_data->lock);
> }
>
> If a concurrent netdev_led_attr_store() or interval_store() acquires
> trigger_data->lock in the window between cancel_delayed_work_sync() and
> mutex_lock(&trigger_data->lock) while carrier_link_up is still true,
> set_baseline_state() will re-arm trigger_data->work.
>
> When netdev_trig_notify() or set_device_name() then acquires
> trigger_data->lock, it sets carrier_link_up = false and sets the LED to
> LED_OFF without cancelling the newly scheduled work. When netdev_trig_work()
> runs, netdev_trig_sw_blink() returns true despite carrier_link_up being
> false, allowing the worker to keep polling, blinking via
> led_blink_set_oneshot(), and rescheduling itself while the link is down
> (and leaving the LED on when any link or duplex mode bit sets invert = 1).
>
> [ ... ]
>
> > @@ -503,10 +520,14 @@ static ssize_t interval_store(struct device *dev,
> >
> > /* impose some basic bounds on the timer interval */
> > if (value >= 5 && value <= 10000) {
> > - cancel_delayed_work_sync(&trigger_data->work);
> > + mutex_lock(&trigger_data->lock);
> > +
> > + cancel_delayed_work(&trigger_data->work);
> >
> > atomic_set(&trigger_data->interval, msecs_to_jiffies(value));
> > set_baseline_state(trigger_data); /* resets timer */
> > +
> > + mutex_unlock(&trigger_data->lock);
> > }
> >
> > return size;
>
> [Severity: Medium]
> Can interval_store() race with concurrent trigger_data->hw_control updates?
>
> At the start of interval_store(), trigger_data->hw_control is checked
> before acquiring trigger_data->lock:
>
> drivers/leds/trigger/ledtrig-netdev.c:interval_store() {
> if (trigger_data->hw_control)
> return -EINVAL;
> ...
> if (value >= 5 && value <= 10000) {
> mutex_lock(&trigger_data->lock);
> }
>
> If trigger_data->hw_control is false during that unlocked check, a
> concurrent netdev_led_attr_store() or netdev_trig_notify() (on NETDEV_UP)
> can acquire trigger_data->lock first, see the default interval in
> can_hw_control(), and set trigger_data->hw_control = true.
>
> When interval_store() then acquires trigger_data->lock, it does not
> re-check trigger_data->hw_control before updating trigger_data->interval
> and calling set_baseline_state(). Doesn't this allow trigger_data->interval
> to be changed to a non-default value while hw_control is active, causing
> subsequent can_hw_control() checks to unexpectedly drop out of hardware
> offload?
>
> [ ... ]
>
> >
> > base-commit: 3d229ce89862b8e82d71a9e11d6f840ca272a6d6
--
Alexander Sverdlin
Siemens AG
www.siemens.com
prev parent reply other threads:[~2026-10-20 14:40 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-20 12:46 [PATCH v5 0/4] leds: trigger: netdev: fix sysfs_update_group() races A. Sverdlin
2026-10-20 12:46 ` [PATCH v5 1/4] leds: trigger: netdev: Put netdev on activate error path A. Sverdlin
2026-10-20 12:51 ` sashiko-bot
2026-10-20 12:46 ` [PATCH v5 2/4] leds: trigger: netdev: Access net_dev under trigger_data->lock in the worker A. Sverdlin
2026-10-20 13:02 ` sashiko-bot
2026-10-20 12:46 ` [PATCH v5 3/4] leds: trigger: netdev: Fix sysfs_update_group() races A. Sverdlin
2026-10-20 12:56 ` sashiko-bot
2026-10-20 12:46 ` [PATCH v5 4/4] leds: trigger: netdev: Serialize mode/interval stores with trigger lock A. Sverdlin
2026-10-20 12:59 ` sashiko-bot
2026-10-20 14:40 ` Sverdlin, Alexander [this message]
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=bcabe7eaf6efdf59b7378fed3533ccc2d44382b1.camel@siemens.com \
--to=alexander.sverdlin@siemens.com \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox