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: <62bbfb0e-20bd-47f7-ada1-7f4d30c888d7@kernel.org>
Date: Mon, 26 Jan 2026 15:34:25 +0900
From: Damien Le Moal <dlemoal@...nel.org>
To: Markus Probst <markus.probst@...teo.de>, Lee Jones <lee@...nel.org>,
 Pavel Machek <pavel@...nel.org>, Rob Herring <robh@...nel.org>,
 Krzysztof Kozlowski <krzk+dt@...nel.org>, Conor Dooley
 <conor+dt@...nel.org>, Jacek Anaszewski <jacek.anaszewski@...il.com>,
 Niklas Cassel <cassel@...nel.org>, John Garry <john.g.garry@...cle.com>,
 Jason Yan <yanaijie@...wei.com>,
 "James E.J. Bottomley" <James.Bottomley@...senPartnership.com>,
 "Martin K. Petersen" <martin.petersen@...cle.com>
Cc: Pavel Machek <pavel@....cz>, linux-leds@...r.kernel.org,
 devicetree@...r.kernel.org, linux-kernel@...r.kernel.org,
 linux-ide@...r.kernel.org, linux-scsi@...r.kernel.org
Subject: Re: [PATCH RFC 4/4] leds: add disk trigger for each ata port

On 1/24/26 4:05 AM, Markus Probst wrote:
> Register a disk trigger for each ata port. This trigger will only show
> the activity for the ata port it has been registered for.
> 
> This allows individual leds to be mapped to one ata port.
> This is especially useful for NAS devices, which have an own led for each
> disk slot.
> 
> Signed-off-by: Markus Probst <markus.probst@...teo.de>
> ---
>  drivers/ata/libata-core.c           |  22 +++++-
>  drivers/leds/trigger/ledtrig-disk.c | 144 ++++++++++++++++++++++++++++++------
>  drivers/scsi/libsas/sas_ata.c       |   3 +-
>  include/linux/leds.h                |  16 +++-
>  include/linux/libata.h              |   6 +-
>  5 files changed, 161 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
> index 09d8c035fcdf..796c46449298 100644
> --- a/drivers/ata/libata-core.c
> +++ b/drivers/ata/libata-core.c
> @@ -4921,8 +4921,10 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
>  	struct ata_device *dev = qc->dev;
>  	struct ata_eh_info *ehi = &dev->link->eh_info;
>  
> +#ifdef CONFIG_LEDS_TRIGGER_DISK
>  	/* Trigger the LED (if available) */
> -	ledtrig_disk_activity(!!(qc->tf.flags & ATA_TFLAG_WRITE));
> +	ledtrig_disk_activity(ap->led_trigger, !!(qc->tf.flags & ATA_TFLAG_WRITE));
> +#endif

Please define an empty wrapper for the !CONFIG_LEDS_TRIGGER_DISK case to avoid
adding this ifdef.

>  
>  	/*
>  	 * In order to synchronize EH with the regular execution path, a qc that
> @@ -5538,10 +5540,13 @@ int sata_link_init_spd(struct ata_link *link)
>   *	LOCKING:
>   *	Inherited from calling layer (may sleep).
>   */
> -struct ata_port *ata_port_alloc(struct ata_host *host)
> +struct ata_port *ata_port_alloc(struct ata_host *host, int port_no)
>  {
>  	struct ata_port *ap;
>  	int id;
> +#ifdef CONFIG_LEDS_TRIGGER_DISK
> +	char name[32];
> +#endif
>  
>  	ap = kzalloc(sizeof(*ap), GFP_KERNEL);
>  	if (!ap)
> @@ -5557,6 +5562,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
>  	ap->print_id = id;
>  	ap->host = host;
>  	ap->dev = host->dev;
> +	ap->port_no = port_no;

Please extract this change in a prep patch.

>  
>  	mutex_init(&ap->scsi_scan_mutex);
>  	INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug);
> @@ -5579,6 +5585,11 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
>  
>  	ata_force_pflags(ap);
>  
> +#ifdef CONFIG_LEDS_TRIGGER_DISK
> +	if (snprintf(name, sizeof(name), "%s-ata%d", dev_name(host->dev), port_no) < sizeof(name))
> +		ap->led_trigger = ledtrig_disk_trigger_register(name);
> +#endif

Same here: please define a helper function which is void for the
!CONFIG_LEDS_TRIGGER_DISK case. That will avoid both ifdefs here. Sprinkling
the code with such ifdef makes maintenance a nightmare. Wrap everything to
avoid that please.

> +
>  	return ap;
>  }
>  EXPORT_SYMBOL_GPL(ata_port_alloc);
> @@ -5588,6 +5599,10 @@ void ata_port_free(struct ata_port *ap)
>  	if (!ap)
>  		return;
>  
> +#ifdef CONFIG_LEDS_TRIGGER_DISK
> +	ledtrig_disk_trigger_unregister(ap->led_trigger);
> +#endif

Same comment. Use a void function or null macro to define this for the
!CONFIG_LEDS_TRIGGER_DISK case.

> +
>  	kfree(ap->pmp_link);
>  	kfree(ap->slave_link);
>  	ida_free(&ata_ida, ap->print_id);
> @@ -5690,11 +5705,10 @@ struct ata_host *ata_host_alloc(struct device *dev, int n_ports)
>  	for (i = 0; i < n_ports; i++) {
>  		struct ata_port *ap;
>  
> -		ap = ata_port_alloc(host);
> +		ap = ata_port_alloc(host, i);
>  		if (!ap)
>  			goto err_out;
>  
> -		ap->port_no = i;
>  		host->ports[i] = ap;
>  	}
>  
> diff --git a/drivers/leds/trigger/ledtrig-disk.c b/drivers/leds/trigger/ledtrig-disk.c
> index ed5ef83a5b35..fd25b4e45fb4 100644
> --- a/drivers/leds/trigger/ledtrig-disk.c
> +++ b/drivers/leds/trigger/ledtrig-disk.c

Can you try to split this part into a prep patch to avoid mixing led code and
ata code ?

> @@ -159,20 +159,22 @@ static int ledtrig_disk_activate(struct led_classdev *led_cdev)
>  	return 0;
>  }
>  
> -static struct led_trigger ledtrig_disk = {
> -	.name = "disk-activity",
> -	.activate = ledtrig_disk_activate,
> -	.groups = ledtrig_disk_groups,
> -};
> -static struct led_trigger ledtrig_disk_read = {
> -	.name = "disk-read",
> -	.activate = ledtrig_disk_activate,
> -	.groups = ledtrig_disk_groups,
> -};
> -static struct led_trigger ledtrig_disk_write = {
> -	.name = "disk-write",
> -	.activate = ledtrig_disk_activate,
> -	.groups = ledtrig_disk_groups,
> +static struct ledtrig_disk_trigger ledtrig_disk = {
> +	.all = {
> +		.name = "disk-activity",
> +		.activate = ledtrig_disk_activate,
> +		.groups = ledtrig_disk_groups,
> +	},
> +	.read = {
> +		.name = "disk-read",
> +		.activate = ledtrig_disk_activate,
> +		.groups = ledtrig_disk_groups,
> +	},
> +	.write = {
> +		.name = "disk-write",
> +		.activate = ledtrig_disk_activate,
> +		.groups = ledtrig_disk_groups,
> +	},
>  };
>  
>  static void ledtrig_disk_blink_oneshot(struct led_trigger *trig)
> @@ -189,21 +191,121 @@ static void ledtrig_disk_blink_oneshot(struct led_trigger *trig)
>  	rcu_read_unlock();
>  }
>  
> -void ledtrig_disk_activity(bool write)
> +static void ledtrig_disk_trigger_activity(struct ledtrig_disk_trigger *trig, bool write)
>  {
> -	ledtrig_disk_blink_oneshot(&ledtrig_disk);
> +	if (IS_ERR_OR_NULL(trig))
> +		return;
> +	ledtrig_disk_blink_oneshot(&trig->all);
>  	if (write)
> -		ledtrig_disk_blink_oneshot(&ledtrig_disk_write);
> +		ledtrig_disk_blink_oneshot(&trig->write);
>  	else
> -		ledtrig_disk_blink_oneshot(&ledtrig_disk_read);
> +		ledtrig_disk_blink_oneshot(&trig->read);
> +}
> +
> +void ledtrig_disk_activity(struct ledtrig_disk_trigger *port, bool write)
> +{
> +	ledtrig_disk_trigger_activity(&ledtrig_disk, write);
> +	ledtrig_disk_trigger_activity(port, write);
>  }
>  EXPORT_SYMBOL(ledtrig_disk_activity);
>  
> +struct ledtrig_disk_trigger *ledtrig_disk_trigger_register(const char *name)
> +{
> +	struct ledtrig_disk_trigger *trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
> +	int ret, n;
> +
> +	if (!trigger)
> +		return ERR_PTR(-ENOMEM);
> +
> +	trigger->all.name = kzalloc(TRIG_NAME_MAX, GFP_KERNEL);
> +	if (!trigger->all.name) {
> +		ret = -ENOMEM;
> +		goto err1;
> +	}
> +
> +	n = snprintf((char *)trigger->all.name, TRIG_NAME_MAX, "%s-disk-activity", name);
> +	if (n >= TRIG_NAME_MAX) {
> +		ret = -E2BIG;
> +		goto err1;
> +	}
> +
> +	trigger->all.activate = ledtrig_disk_activate;
> +	trigger->all.groups = ledtrig_disk_groups;
> +
> +	ret = led_trigger_register(&trigger->all);
> +	if (ret)
> +		goto err1;
> +
> +	trigger->read.name = kzalloc(TRIG_NAME_MAX, GFP_KERNEL);
> +	if (!trigger->read.name) {
> +		ret = -ENOMEM;
> +		goto err2;
> +	}
> +
> +	n = snprintf((char *)trigger->read.name, TRIG_NAME_MAX, "%s-disk-read", name);
> +	if (n >= TRIG_NAME_MAX) {
> +		ret = -E2BIG;
> +		goto err2;
> +	}
> +
> +	trigger->read.activate = ledtrig_disk_activate;
> +	trigger->read.groups = ledtrig_disk_groups;
> +
> +	ret = led_trigger_register(&trigger->read);
> +	if (ret)
> +		goto err2;
> +
> +	trigger->write.name = kzalloc(TRIG_NAME_MAX, GFP_KERNEL);
> +	if (!trigger->write.name) {
> +		ret = -ENOMEM;
> +		goto err3;
> +	}
> +
> +	n = snprintf((char *)trigger->write.name, TRIG_NAME_MAX, "%s-disk-write", name);
> +	if (n >= TRIG_NAME_MAX) {
> +		ret = -E2BIG;
> +		goto err3;
> +	}
> +
> +	trigger->write.activate = ledtrig_disk_activate;
> +	trigger->write.groups = ledtrig_disk_groups;
> +
> +	ret = led_trigger_register(&trigger->write);
> +	if (ret)
> +		goto err3;
> +
> +	return trigger;
> +
> +err3:
> +	led_trigger_unregister(&trigger->read);
> +err2:
> +	led_trigger_unregister(&trigger->all);
> +err1:
> +	kfree(trigger->all.name);
> +	kfree(trigger->read.name);
> +	kfree(trigger->write.name);
> +	kfree(trigger);
> +
> +	return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL(ledtrig_disk_trigger_register);
> +
> +void ledtrig_disk_trigger_unregister(struct ledtrig_disk_trigger *trig)
> +{
> +	if (IS_ERR_OR_NULL(trig))
> +		return;
> +
> +	led_trigger_unregister(&trig->all);
> +	led_trigger_unregister(&trig->read);
> +	led_trigger_unregister(&trig->write);
> +}
> +EXPORT_SYMBOL(ledtrig_disk_trigger_unregister);
> +
>  static int __init ledtrig_disk_init(void)
>  {
> -	led_trigger_register(&ledtrig_disk);
> -	led_trigger_register(&ledtrig_disk_read);
> -	led_trigger_register(&ledtrig_disk_write);
> +	led_trigger_register(&ledtrig_disk.all);
> +	led_trigger_register(&ledtrig_disk.read);
> +	led_trigger_register(&ledtrig_disk.write);
>  
>  	return 0;
>  }
> diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
> index bcecb4911da9..8841850684f7 100644
> --- a/drivers/scsi/libsas/sas_ata.c
> +++ b/drivers/scsi/libsas/sas_ata.c
> @@ -587,14 +587,13 @@ int sas_ata_init(struct domain_device *found_dev)
>  
>  	ata_host_init(ata_host, ha->dev, &sas_sata_ops);
>  
> -	ap = ata_port_alloc(ata_host);
> +	ap = ata_port_alloc(ata_host, 0);
>  	if (!ap) {
>  		pr_err("ata_port_alloc failed.\n");
>  		rc = -ENODEV;
>  		goto free_host;
>  	}
>  
> -	ap->port_no = 0;
>  	ap->pio_mask = ATA_PIO4;
>  	ap->mwdma_mask = ATA_MWDMA2;
>  	ap->udma_mask = ATA_UDMA6;
> diff --git a/include/linux/leds.h b/include/linux/leds.h
> index b16b803cc1ac..3221be97e9c0 100644
> --- a/include/linux/leds.h
> +++ b/include/linux/leds.h
> @@ -619,10 +619,22 @@ enum led_trigger_netdev_modes {
>  };
>  
>  /* Trigger specific functions */
> +struct ledtrig_disk_trigger {
> +	struct led_trigger all;
> +	struct led_trigger read;
> +	struct led_trigger write;
> +};
>  #ifdef CONFIG_LEDS_TRIGGER_DISK
> -void ledtrig_disk_activity(bool write);
> +struct ledtrig_disk_trigger *ledtrig_disk_trigger_register(const char *name);
> +void ledtrig_disk_trigger_unregister(struct ledtrig_disk_trigger *trig);
> +void ledtrig_disk_activity(struct ledtrig_disk_trigger *port, bool write);
>  #else
> -static inline void ledtrig_disk_activity(bool write) {}
> +static inline struct ledtrig_disk_trigger *ledtrig_disk_trigger_register(const char *name)
> +{
> +	return ERR_PTR(-EOPNOTSUPP);
> +}
> +static inline void ledtrig_disk_trigger_unregister(struct ledtrig_disk_trigger *trig) {}
> +static inline void ledtrig_disk_activity(struct ledtrig_disk_trigger *port, bool write) {}
>  #endif
>  
>  #ifdef CONFIG_LEDS_TRIGGER_MTD
> diff --git a/include/linux/libata.h b/include/linux/libata.h
> index 39534fafa36a..50124d170d13 100644
> --- a/include/linux/libata.h
> +++ b/include/linux/libata.h
> @@ -940,6 +940,10 @@ struct ata_port {
>  #ifdef CONFIG_ATA_ACPI
>  	struct ata_acpi_gtm	__acpi_init_gtm; /* use ata_acpi_init_gtm() */
>  #endif
> +
> +#ifdef CONFIG_LEDS_TRIGGER_DISK
> +	struct ledtrig_disk_trigger *led_trigger;
> +#endif
>  };
>  
>  /* The following initializer overrides a method to NULL whether one of
> @@ -1307,7 +1311,7 @@ extern int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
>  			     bool spm_wakeup);
>  extern int ata_slave_link_init(struct ata_port *ap);
>  extern void ata_port_probe(struct ata_port *ap);
> -extern struct ata_port *ata_port_alloc(struct ata_host *host);
> +extern struct ata_port *ata_port_alloc(struct ata_host *host, int port_no);
>  extern void ata_port_free(struct ata_port *ap);
>  extern int ata_tport_add(struct device *parent, struct ata_port *ap);
>  extern void ata_tport_delete(struct ata_port *ap);
> 


-- 
Damien Le Moal
Western Digital Research

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ