Linux LED subsystem development
 help / color / mirror / Atom feed
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

      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