lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <7e8860574413505c314bdfd0f3e10188@dev.tdt.de>
Date:   Mon, 23 Oct 2023 14:15:55 +0200
From:   Florian Eckert <fe@....tdt.de>
To:     Greg KH <gregkh@...uxfoundation.org>
Cc:     Eckert.Florian@...glemail.com, jirislaby@...nel.org, pavel@....cz,
        lee@...nel.org, kabel@...nel.org, u.kleine-koenig@...gutronix.de,
        m.brock@...mierlo.com, linux-kernel@...r.kernel.org,
        linux-serial@...r.kernel.org, linux-leds@...r.kernel.org
Subject: Re: [PATCH v5 2/2] leds: ledtrig-tty: add new line mode evaluation


On 2023-10-23 12:06, Greg KH wrote:
>> ---
>>  .../ABI/testing/sysfs-class-led-trigger-tty   |  54 +++++
>>  drivers/leds/trigger/ledtrig-tty.c            | 187 
>> ++++++++++++++++--
>>  2 files changed, 230 insertions(+), 11 deletions(-)
>> 
>> diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-tty 
>> b/Documentation/ABI/testing/sysfs-class-led-trigger-tty
>> index 2bf6b24e781b..08127b1a4602 100644
>> --- a/Documentation/ABI/testing/sysfs-class-led-trigger-tty
>> +++ b/Documentation/ABI/testing/sysfs-class-led-trigger-tty
>> @@ -4,3 +4,57 @@ KernelVersion:	5.10
>>  Contact:	linux-leds@...r.kernel.org
>>  Description:
>>  		Specifies the tty device name of the triggering tty
>> +
>> +What:		/sys/class/leds/<led>/rx
>> +Date:		October 2023
>> +KernelVersion:	6.7
>> +Description:
>> +		Signal reception (rx) of data on the named tty device.
>> +		If set to 0, the LED will not blink on reception.
>> +		If set to 1 (default), the LED will blink on reception.
>> +
>> +What:		/sys/class/leds/<led>/tx
>> +Date:		October 2023
>> +KernelVersion:	6.7
>> +Description:
>> +		Signal transmission (tx) of data on the named tty device.
>> +		If set to 0, the LED will not blink on transmission.
>> +		If set to 1 (default), the LED will blink on transmission.
> 
> Were these existing files not documented already?  If not, they should
> be a separate patch we can take now.
> 
>> +
>> +car rng
> 
> What is that line for?

Oops, my fault!

> 
>> +What:		/sys/class/leds/<led>/line_cts
> 
> Why are these all "line_" now?  What is wrong with just "cts" and "dsr"
> and the like?  That keeps them in sync with the "rx" and "tx" files,
> right?

I can change that, I just thought it makes sense to prefix the line 
state
to emphasize the meaning compared to rx and tx.

>> +Date:		October 2023
> 
> October ends in a few days, I think this needs some more work.

But then that's tricky! I do not know when the 6.8 is released. February 
2024?

>> +KernelVersion:	6.7
> 
> And trees should probably be closed now, this looks like 6.8 stuff.


Ok will change this to 6.8

>> +Description:
>> +		DCE is ready to accept data from the DTE (Clear To Send). If
>> +		the line state is detected, the LED is switched on.
>> +		If set to 0 (default), the LED will not evaluate CTS.
>> +		If set to 1, the LED will evaluate CTS.
>> +
>> +What:		/sys/class/leds/<led>/line_dsr
>> +Date:		October 2023
>> +KernelVersion:	6.7
>> +Description:
>> +		DCE is ready to receive and send data (Data Set Ready). If
>> +		the line state is detected, the LED is switched on.
>> +		If set to 0 (default), the LED will not evaluate DSR.
>> +		If set to 1, the LED will evaluate DSR.
>> +
>> +What:		/sys/class/leds/<led>/line_car
>> +Date:		October 2023
>> +KernelVersion:	6.7
>> +Description:
>> +		DTE is receiving a carrier from the DCE (Data Carrier Detect).
>> +		If the line state is detected, the LED is switched on.
>> +		If set to 0 (default), the LED will not evaluate CAR (DCD).
>> +		If set to 1, the LED will evaluate CAR (DCD).
>> +
>> +What:		/sys/class/leds/<led>/line_cts
>> +Date:		October 2023
>> +KernelVersion:	6.7
>> +Description:
>> +		DCE has detected an incoming ring signal on the telephone
>> +		line (Ring Indicator). If the line state is detected, the
>> +		LED is switched on.
>> +		If set to 0 (default), the LED will not evaluate RNG (RI).
>> +		If set to 1, the LED will evaluate RNG (RI).
>> diff --git a/drivers/leds/trigger/ledtrig-tty.c 
>> b/drivers/leds/trigger/ledtrig-tty.c
>> index 8ae0d2d284af..5c8aea1791cf 100644
>> --- a/drivers/leds/trigger/ledtrig-tty.c
>> +++ b/drivers/leds/trigger/ledtrig-tty.c
>> @@ -16,6 +16,28 @@ struct ledtrig_tty_data {
>>  	const char *ttyname;
>>  	struct tty_struct *tty;
>>  	int rx, tx;
>> +	unsigned long ttytrigger;
> 
> Please explain why "unsigned long" is needed here.

As described by me a few lines below and wanted by you, I will change 
this to
boolean flags for rx,tx,cts,dsr,car and rng.

> 
>> +};
>> +
>> +/* Indicates which state the LED should now display */
>> +enum led_trigger_tty_state {
>> +	TTY_LED_BLINK,
>> +	TTY_LED_ENABLE,
>> +	TTY_LED_DISABLE,
>> +};
> 
> Shouldn't we need these states for rx/tx already?

Before my change, the LED has only flashed if there was a transmission.
This is now the TTY_LED_BLINK state. I could rename this to
TTY_LED_FLASH if that is more familiar.

>> +
>> +/* This enum is used to read and write the ttytrigger selection via 
>> the
>> + * sysfs entry and also to evaluate the TIOCM_* bits.
>> + */
>> +enum led_trigger_tty_bits {
>> +	TRIGGER_TTY_RX = 0,
>> +	TRIGGER_TTY_TX,
>> +	TRIGGER_TTY_CTS,
>> +	TRIGGER_TTY_DSR,
>> +	TRIGGER_TTY_CAR,
>> +	TRIGGER_TTY_RNG,
> 
> These are bit values (more on that below), so please explicitly set 
> them
> to a value.

OK

> 
>> +	/* Keep last */
>> +	__TRIGGER_TTY_MAX,
> 
> You never use this, so it is not needed at all.

I saw it in other source files, so I added it. I thought this was
common in the kernel. If this is not the case I will remove this in
the next round.

>>  };
>> 
>>  static void ledtrig_tty_restart(struct ledtrig_tty_data 
>> *trigger_data)
>> @@ -78,13 +100,94 @@ static ssize_t ttyname_store(struct device *dev,
>>  }
>>  static DEVICE_ATTR_RW(ttyname);
>> 
>> +static ssize_t ledtrig_tty_attr_show(struct device *dev, char *buf,
>> +	enum led_trigger_tty_bits attr)
>> +{
>> +	struct ledtrig_tty_data *trigger_data = 
>> led_trigger_get_drvdata(dev);
>> +	int trigger;
>> +
>> +	switch (attr) {
>> +	case TRIGGER_TTY_RX:
>> +	case TRIGGER_TTY_TX:
>> +	case TRIGGER_TTY_CTS:
>> +	case TRIGGER_TTY_DSR:
>> +	case TRIGGER_TTY_CAR:
>> +	case TRIGGER_TTY_RNG:
>> +		trigger = attr;
>> +		break;
>> +	default:
>> +		return -EINVAL;
> 
> How can default ever happen?

If I use the DEFINE_TTY_TRIGGER then this cannot happen.
This is an artifact from when I didn't used the DEFINE_TTY_TRIGGER 
macro.
I will remove it in the next round.

>> +	}
>> +
>> +	return sysfs_emit(buf, "%u\n", test_bit(trigger, 
>> &trigger_data->ttytrigger));
>> +}
>> +
>> +static ssize_t ledtrig_tty_attr_store(struct device *dev, const char 
>> *buf,
>> +	size_t size, enum led_trigger_tty_bits attr)
>> +{
>> +	struct ledtrig_tty_data *trigger_data = 
>> led_trigger_get_drvdata(dev);
>> +	bool enable;
>> +	int trigger;
>> +	int ret;
>> +
>> +	ret = kstrtobool(buf, &enable);
>> +	if (ret)
>> +		return ret;
>> +
>> +	switch (attr) {
>> +	case TRIGGER_TTY_RX:
>> +	case TRIGGER_TTY_TX:
>> +	case TRIGGER_TTY_CTS:
>> +	case TRIGGER_TTY_DSR:
>> +	case TRIGGER_TTY_CAR:
>> +	case TRIGGER_TTY_RNG:
>> +		trigger = attr;
>> +		break;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	if (enable)
>> +		set_bit(trigger, &trigger_data->ttytrigger);
>> +	else
>> +		clear_bit(trigger, &trigger_data->ttytrigger);
>> +
>> +	return size;
>> +}
>> +
>> +#define DEFINE_TTY_TRIGGER(trigger_name, trigger) \
>> +	static ssize_t trigger_name##_show(struct device *dev, \
>> +		struct device_attribute *attr, char *buf) \
>> +	{ \
>> +		return ledtrig_tty_attr_show(dev, buf, trigger); \
>> +	} \
>> +	static ssize_t trigger_name##_store(struct device *dev, \
>> +		struct device_attribute *attr, const char *buf, size_t size) \
>> +	{ \
>> +		return ledtrig_tty_attr_store(dev, buf, size, trigger); \
>> +	} \
>> +	static DEVICE_ATTR_RW(trigger_name)
>> +
>> +DEFINE_TTY_TRIGGER(rx, TRIGGER_TTY_RX);
>> +DEFINE_TTY_TRIGGER(tx, TRIGGER_TTY_TX);
> 
> Again, I thought we supported rx/tx already?  If so, this should be
> split out into "redo the rx/tx into a new style" and then "add new
> attributes".  Well maybe, more below...

Yes, but the trigger rx/tx was already support before my change.
It could not be configured via the sysfs.

In my setup I do not want to show if data is being transferred.
I want to display the line stats.
Therefore I made it configurable to turn it off.

>> +DEFINE_TTY_TRIGGER(line_cts, TRIGGER_TTY_CTS);
>> +DEFINE_TTY_TRIGGER(line_dsr, TRIGGER_TTY_DSR);
>> +DEFINE_TTY_TRIGGER(line_car, TRIGGER_TTY_CAR);
>> +DEFINE_TTY_TRIGGER(line_rng, TRIGGER_TTY_RNG);
>> +
>>  static void ledtrig_tty_work(struct work_struct *work)
>>  {
>>  	struct ledtrig_tty_data *trigger_data =
>>  		container_of(work, struct ledtrig_tty_data, dwork.work);
>> +	struct led_classdev *led_cdev = trigger_data->led_cdev;
>> +	unsigned long interval = LEDTRIG_TTY_INTERVAL;
>>  	struct serial_icounter_struct icount;
>> +	enum led_trigger_tty_state state;
>> +	int current_brightness;
>> +	int status;
>>  	int ret;
>> 
>> +	state = TTY_LED_DISABLE;
>>  	mutex_lock(&trigger_data->mutex);
>> 
>>  	if (!trigger_data->ttyname) {
>> @@ -115,22 +218,74 @@ static void ledtrig_tty_work(struct work_struct 
>> *work)
>>  		trigger_data->tty = tty;
>>  	}
>> 
>> -	ret = tty_get_icount(trigger_data->tty, &icount);
>> -	if (ret) {
>> -		dev_info(trigger_data->tty->dev, "Failed to get icount, stopped 
>> polling\n");
>> -		mutex_unlock(&trigger_data->mutex);
>> -		return;
>> +	status = tty_get_tiocm(trigger_data->tty);
>> +	if (status > 0) {
>> +		if (test_bit(TRIGGER_TTY_CTS, &trigger_data->ttytrigger)) {
>> +			if (status & TIOCM_CTS)
>> +				state = TTY_LED_ENABLE;
>> +		}
>> +
>> +		if (test_bit(TRIGGER_TTY_DSR, &trigger_data->ttytrigger)) {
>> +			if (status & TIOCM_DSR)
>> +				state = TTY_LED_ENABLE;
>> +		}
>> +
>> +		if (test_bit(TRIGGER_TTY_CAR, &trigger_data->ttytrigger)) {
>> +			if (status & TIOCM_CAR)
>> +				state = TTY_LED_ENABLE;
>> +		}
>> +
>> +		if (test_bit(TRIGGER_TTY_RNG, &trigger_data->ttytrigger)) {
>> +			if (status & TIOCM_RNG)
>> +				state = TTY_LED_ENABLE;
>> +		}
> 
> Let's ask why you are using bits at all here.  Why?  What is it helping
> with?  Is it faster than a normal "bool" value?  I am guessing not
> (requires mask and test instead of just test).
> 
> So let's just make these individual values in the structure, that makes
> things much simpler and easier and you never have to worry about bit
> field values anywhere.  And the end code will be easier to read as well
> as probably faster (which matters in this codepath, right?)

I had never thought of it that way. I will have a look at that.
Thanks for this.

>> +	}
>> +
>> +	/* The rx/tx handling must come after the evaluation of TIOCM_*,
>> +	 * since the display for rx/tx has priority
>> +	 */
>> +	if (test_bit(TRIGGER_TTY_RX, &trigger_data->ttytrigger) ||
>> +	    test_bit(TRIGGER_TTY_TX, &trigger_data->ttytrigger)) {
>> +		ret = tty_get_icount(trigger_data->tty, &icount);
>> +		if (ret) {
>> +			dev_info(trigger_data->tty->dev, "Failed to get icount, stopped 
>> polling\n");
> 
> Not your fault, but this should NOT be "dev_info()" but rather,
> "dev_err()", or "dev_warn()".

This is what I have adopted from the code before my change.
But it will change this in dev_warn.

> 
>> +			mutex_unlock(&trigger_data->mutex);
> 
> This looks ready-made for the completion.h usage so we always make sure
> to drop the mutex when done.

I'll have to take a closer look, I don't know that one.
This is what I have adopted from the code before my change.
Shouldn't that be done in a different patch set?

>> +			return;
>> +		}
>> +
>> +		if (test_bit(TRIGGER_TTY_RX, &trigger_data->ttytrigger) &&
>> +		    (icount.tx != trigger_data->tx)) {
>> +			trigger_data->tx = icount.tx;
>> +			state = TTY_LED_BLINK;
>> +		}
>> +
>> +		if (test_bit(TRIGGER_TTY_TX, &trigger_data->ttytrigger) &&
>> +		    (icount.rx != trigger_data->rx)) {
>> +			trigger_data->rx = icount.rx;
>> +			state = TTY_LED_BLINK;
>> +		}
>>  	}
>> 
>> -	if (icount.rx != trigger_data->rx ||
>> -	    icount.tx != trigger_data->tx) {
>> -		unsigned long interval = LEDTRIG_TTY_INTERVAL;
>> +	current_brightness = led_cdev->brightness;
>> +	if (current_brightness)
>> +		led_cdev->blink_brightness = current_brightness;
>> 
>> +	if (!led_cdev->blink_brightness)
>> +		led_cdev->blink_brightness = led_cdev->max_brightness;
>> +
>> +	switch (state) {
>> +	case TTY_LED_BLINK:
>>  		led_blink_set_oneshot(trigger_data->led_cdev, &interval,
>>  				      &interval, 0);
>> -
>> -		trigger_data->rx = icount.rx;
>> -		trigger_data->tx = icount.tx;
>> +		break;
>> +	case TTY_LED_ENABLE:
>> +		led_set_brightness(led_cdev, led_cdev->blink_brightness);
>> +		break;
>> +	case TTY_LED_DISABLE:
>> +		fallthrough;
>> +	default:
>> +		led_set_brightness(led_cdev, LED_OFF);
>> +		break;
>>  	}
>> 
>>  out:
>> @@ -141,6 +296,12 @@ static void ledtrig_tty_work(struct work_struct 
>> *work)
>> 
>>  static struct attribute *ledtrig_tty_attrs[] = {
>>  	&dev_attr_ttyname.attr,
>> +	&dev_attr_rx.attr,
>> +	&dev_attr_tx.attr,
> 
> Again, I thought we had rx/tx already?  If not, how was that controlled
> today?

It could not be controlled! The LED flashed when data where transferred.
This was the only function that the trigger supported.

Thanks for your review!

---
Florian

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ