LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [RFC PATCH v3 00/18] Add block device LED trigger
@ 2021-08-19  2:50 Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 01/18] docs: Add block device (blkdev) LED trigger documentation Ian Pilcher
                   ` (17 more replies)
  0 siblings, 18 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

Ridiculous or not, here is version 3 of the block device trigger for
"freaking blinkenlights".  It addresses basically all of the points
raised in response to the v2 patchset.

* The main body of the code is moved from the block directory into
  the LED triggers directory (drivers/leds/trigger/ledtrig-blkdev.c)

  The downside of this is that it requires adding an API to the
  block subsystem - get_disk_by_name() - which allows the trigger
  code to resolve a gendisk when asked to monitor it.  I know of
  no good way to do this today, and I don't know of a good way to
  implement the sysfs API requested by Pavel and Marek without
  something like this API.

  Other than that, changes to the block subsystem are as minimal as
  I can make them - a single pointer added to struct gendisk and
  init/cleanup calls when a gendisk is added or deleted.

* This also implements Marek's suggestion of periodically checking
  devices for activity, rather than directly blinking LEDs in the
  I/O path.  This change has the unanticipated benefit of making the
  trigger work on pretty much all types of virtual block devices
  (device mapper, MD RAID, zRAM, etc.), as well as NVMe SSDs.

* Relationships between devices and LEDs are now many-to-many.  An
  LED can monitor multiple devices, and multiple LEDs can monitor
  any one device.  The current "associations" are reflected in two
  sysfs directories.

  - /sys/class/leds/<led>/block_devices contains links to all devices
    associated with an LED, and

  - /sys/block/<disk>/blkdev_leds contains links to all LEDs with
    which the device is associated.

  (The latter directory only exists when the device is associated
  with at least one LED.)

* Each LED can be set to show read activity, write activity, or both.
  Discards and cache flushes are considered to be writes, as they
  affect the state of the device's non-volatile storage.

Ian Pilcher (18):
  docs: Add block device (blkdev) LED trigger documentation
  block: Add get_disk_by_name() for use by blkdev LED trigger
  ledtrig-blkdev: Add file (ledtrig-blkdev.c) for block device LED
    trigger
  ledtrig-blkdev: Add misc. helper functions to blkdev LED trigger
  ledtrig-blkdev: Periodically check devices for activity & blink LEDs
  block: Add LED trigger pointer to struct gendisk
  ledtrig-blkdev: Add function to initialize gendisk ledtrig member
  ledtrig-blkdev: Add function to remove LED/device association
  ledtrig-blkdev: Add function to disassociate a device from all LEDs
  block: Call LED trigger init/cleanup functions
  ledtrig-blkdev: Add function to associate a device with an LED
  ledtrig-blkdev: Add sysfs attributes to [dis]associate LEDs & devices
  ledtrig-blkdev: Add blink_time & interval sysfs attributes
  ledtrig-blkdev: Add mode (read/write/rw) sysfs attributue
  ledtrig-blkdev: Add function to associate blkdev trigger with LED
  ledtrig-blkdev: Add function to disassociate an LED from the trigger
  ledtrig-blkdev: Add initialization function
  ledtrig-blkdev: Add config option to enable the trigger

 Documentation/ABI/testing/sysfs-block         |   9 +
 .../testing/sysfs-class-led-trigger-blkdev    |  48 ++
 Documentation/leds/index.rst                  |   1 +
 Documentation/leds/ledtrig-blkdev.rst         | 132 +++
 block/genhd.c                                 |  28 +
 drivers/leds/trigger/Kconfig                  |   9 +
 drivers/leds/trigger/Makefile                 |   1 +
 drivers/leds/trigger/ledtrig-blkdev.c         | 770 ++++++++++++++++++
 include/linux/genhd.h                         |  13 +
 include/linux/leds.h                          |  20 +
 10 files changed, 1031 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-class-led-trigger-blkdev
 create mode 100644 Documentation/leds/ledtrig-blkdev.rst
 create mode 100644 drivers/leds/trigger/ledtrig-blkdev.c

-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 01/18] docs: Add block device (blkdev) LED trigger documentation
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 02/18] block: Add get_disk_by_name() for use by blkdev LED trigger Ian Pilcher
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

Add Documentation/ABI/testing/sysfs-class-led-trigger-blkdev to
document:

  * /sys/class/leds/<led>/blink_time
  * /sys/class/leds/<led>/interval
  * /sys/class/leds/<led>/mode
  * /sys/class/leds/<led>/add_blkdev
  * /sys/class/leds/<led>/delete_blkdev
  * /sys/class/leds/<led>/block_devices

Add /sys/block/<disk>/blkdev_leds to Documentation/ABI/testing/sysfs-block

Add overview in Documentation/leds/ledtrig-blkdev.rst

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 Documentation/ABI/testing/sysfs-block         |   9 ++
 .../testing/sysfs-class-led-trigger-blkdev    |  48 +++++++
 Documentation/leds/index.rst                  |   1 +
 Documentation/leds/ledtrig-blkdev.rst         | 132 ++++++++++++++++++
 4 files changed, 190 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-class-led-trigger-blkdev
 create mode 100644 Documentation/leds/ledtrig-blkdev.rst

diff --git a/Documentation/ABI/testing/sysfs-block b/Documentation/ABI/testing/sysfs-block
index e34cdeeeb9d4..702601d6a276 100644
--- a/Documentation/ABI/testing/sysfs-block
+++ b/Documentation/ABI/testing/sysfs-block
@@ -316,3 +316,12 @@ Description:
 		does not complete in this time then the block driver timeout
 		handler is invoked. That timeout handler can decide to retry
 		the request, to fail it or to start a device recovery strategy.
+
+What:		/sys/block/<disk>/blkdev_leds
+Date:		August 2021
+Contact:	Ian Pilcher <arequipeno@gmail.com>
+Description:
+		Directory containing links to all LEDs that are associated
+		with this block device through the blkdev LED trigger.  Only
+		present when at least one LED is associated.  (See
+		Documentation/leds/ledtrig-blkdev.rst.)
diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-blkdev b/Documentation/ABI/testing/sysfs-class-led-trigger-blkdev
new file mode 100644
index 000000000000..1fd164983f13
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-led-trigger-blkdev
@@ -0,0 +1,48 @@
+What:		/sys/class/leds/<led>/blink_time
+Date:		August 2021
+Contact:	Ian Pilcher <arequipeno@gmail.com>
+Description:
+		Time (in milliseconds) that the LED will be on during a single
+		"blink".
+
+What:		/sys/class/leds/<led>/interval
+Date:		August 2021
+Contact:	Ian Pilcher <arequipeno@gmail.com>
+Description:
+		Frequency (in milliseconds) with which block devices associated
+		with the blkdev LED trigger will be checked for activity.
+
+		NOTE that this attribute is a global setting.  All changes
+		apply to all LEDs associated with the blkdev LED trigger.
+
+What:		/sys/class/leds/<led>/mode
+Date:		August 2021
+Contact:	Ian Pilcher <arequipeno@gmail.com>
+Description:
+		Type of events for which LED will blink - read, write,
+		or rw (both).  Note that any activity that changes the state of
+		the device's non-volatile storage (including discards and cache
+		flushes) is considered to be a write.
+
+What:		/sys/class/leds/<led>/add_blkdev
+Date:		August 2021
+Contact:	Ian Pilcher <arequipeno@gmail.com>
+Description:
+		Associate a block device with this LED by writing its kernel
+		name (as shown in /sys/block) to this attribute.  Multiple
+		device names may be written at once, separated by whitespace.
+
+What:		/sys/class/leds/<led>/delete_blkdev
+Date:		August 2021
+Contact:	Ian Pilcher <arequipeno@gmail.com>
+Description:
+		Remove the association between this LED and a block device by
+		writing the device's kernel name to this attribute.  Multiple
+		device names may be written at once, separated by whitespace.
+
+What:		/sys/class/leds/<led>/block_devices
+Date:		August 2021
+Contact:	Ian Pilcher <arequipeno@gmail.com>
+Description:
+		Directory containing links to all block devices that are
+		associated with this LED.
diff --git a/Documentation/leds/index.rst b/Documentation/leds/index.rst
index e5d63b940045..e3c24e468cbc 100644
--- a/Documentation/leds/index.rst
+++ b/Documentation/leds/index.rst
@@ -10,6 +10,7 @@ LEDs
    leds-class
    leds-class-flash
    leds-class-multicolor
+   ledtrig-blkdev
    ledtrig-oneshot
    ledtrig-transient
    ledtrig-usbport
diff --git a/Documentation/leds/ledtrig-blkdev.rst b/Documentation/leds/ledtrig-blkdev.rst
new file mode 100644
index 000000000000..0b1a9359ec39
--- /dev/null
+++ b/Documentation/leds/ledtrig-blkdev.rst
@@ -0,0 +1,132 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=================================
+Block Device (blkdev) LED Trigger
+=================================
+
+Available when ``CONFIG_LEDS_TRIGGER_BLKDEV=y``.
+
+See also:
+
+* ``Documentation/ABI/testing/sysfs-class-led-trigger-blkdev``
+* ``Documentation/ABI/testing/sysfs-block`` (``/sys/block/<disk>/leds``)
+
+Overview
+========
+
+.. note::
+	The examples below use ``<LED>`` to refer to the name of a
+	system-specific LED.  If no suitable LED is available on a test
+	system (in a virtual machine, for example), it is possible to
+	use a userspace LED (``Documentation/leds/uleds.rst``).
+
+Associate the LED with the ``blkdev`` LED trigger::
+
+	# echo blkdev > /sys/class/leds/<LED>/trigger
+
+	# cat /sys/class/leds/<LED>/trigger
+	... kbd-ctrlrlock [blkdev] disk-activity ...
+
+Note that several new device attributes are available.
+
+* ``add_blkdev`` and ``delete_blkdev`` are used to associate block devices with
+  this LED, and to remove associations.
+
+* ``mode`` is used to control the type of device activity that will cause this
+  LED to blink - read activity, write activity, or both.  (Note that any
+  activity that changes the state of a device's non-volatile storage is
+  considered to be a write.  This includes discard and cache flush requests.)
+
+* ``blink_time`` is the duration (in milliseconds) of each blink of this LED.
+
+* ``interval`` is the frequency (in milliseconds) with which devices are checked
+  for activity.
+
+* The ``block_devices`` directory will contain a symbolic link to every device
+  that is associated with this LED.
+
+Associate the LED with the block device::
+
+	# echo sda > /sys/class/leds/<LED>/add_blkdev
+
+	# ls /sys/class/leds/<LED>/block_devices
+	sda
+
+Reads and write activity on the device should cause the LED to blink.  The
+duration of each blink (in milliseconds) can be adjusted by setting
+``/sys/class/leds/<LED>/blink_on``, and the minimum delay between blinks can
+be set via ``/sys/class/leds/<LED>/blink_off``.
+
+Associate a second device with the LED::
+
+	# echo sdb > /sys/class/leds/<LED>/add_blkdev
+
+	# ls /sys/class/leds/<LED>/block_devices
+	sda  sdb
+
+When a block device is associated with one or more LEDs, the LEDs are linked
+from the device's ``blkdev_leds`` directory::
+
+	# ls /sys/block/sd{a,b}/blkdev_leds
+	/sys/block/sda/blkdev_leds:
+	<LED>
+
+	/sys/block/sdb/blkdev_leds:
+	<LED>
+
+(The ``blkdev_leds`` directory only exists when the block device is associated
+with at least one LED.)
+
+The ``add_blkdev`` and ``delete_blkdev`` attributes both accept multiple,
+whitespace separated, devices.  For example::
+
+	# echo sda sdb > /sys/class/leds/<LED>/delete_blkdev
+
+	# ls /sys/class/leds/<LED>/block_devices
+
+``interval`` and ``blink_time``
+===============================
+
+* The ``interval`` attribute is a global setting.  Changing the value via
+  ``/sys/class/leds/<LED>/interval`` will affect all LEDs associated with
+  the ``blkdev`` LED trigger.
+
+* All associated devices are checked for activity every ``interval``
+  milliseconds, and a blink is triggered on appropriate LEDs.  The duration
+  of an LED's blink is determined by its ``blink_time`` attribute (also in
+  milliseconds).  Thus (assuming that activity of the relevant type has occurred
+  on one of an LED's associated devices), the LED will be on for ``blink_time``
+  milliseconds and off for ``interval - blink_time`` milliseconds.
+
+* The LED subsystem ignores new blink requests for an LED that is currently in
+  in the process of blinking, so setting a ``blink_time`` greater than or equal
+  to ``interval`` will cause some blinks to be dropped.
+
+* Because of processing times, scheduling latencies, etc., avoiding missed
+  blinks actually requires a difference of at least a few milliseconds between
+  the ``blink_time`` and ``interval``.  The required difference is likely to
+  vary from system to system.  As a  reference, a Thecus N5550 NAS requires a
+  difference of 7 milliseconds (``interval == 100``, ``blink_time == 93``).
+
+* The default values (``interval == 100``, ``blink_time == 75``) cause the LED
+  associated with a continuously active device to blink rapidly.  For a more
+  "constantly on" effect, increase the ``blink_time`` (but not too much; see
+  the previous bullet).
+
+Other Notes
+===========
+
+* Many (possibly all) types of block devices work with this trigger, including:
+
+  * SCSI (including SATA and USB) hard disk drives and SSDs
+  * SCSI (including SATA and USB) optical drives
+  * NVMe SSDs
+  * SD cards
+  * loopback block devices (``/dev/loop*``)
+  * device mapper devices, such as LVM logical volumes
+  * MD RAID devices
+  * zRAM compressed RAM-disks
+
+* The ``blkdev`` LED trigger supports many-to-many device/LED associations.
+  A device can be associated with multiple LEDs, and an LED can be associated
+  with multiple devices.
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 02/18] block: Add get_disk_by_name() for use by blkdev LED trigger
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 01/18] docs: Add block device (blkdev) LED trigger documentation Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 03/18] ledtrig-blkdev: Add file (ledtrig-blkdev.c) for block device " Ian Pilcher
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

Add API that gets a "handle" (pointer & incremented reference count) to a
block device (struct gendisk) by name.  Used by the block device LED
trigger when configuring which device(s) an LED should monitor.

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 block/genhd.c         | 25 +++++++++++++++++++++++++
 include/linux/genhd.h | 10 ++++++++++
 2 files changed, 35 insertions(+)

diff --git a/block/genhd.c b/block/genhd.c
index 298ee78c1bda..e6d7bb709d62 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -1362,3 +1362,28 @@ int bdev_read_only(struct block_device *bdev)
 	return bdev->bd_read_only || get_disk_ro(bdev->bd_disk);
 }
 EXPORT_SYMBOL(bdev_read_only);
+
+static int match_disk_name(struct device *const dev, const void *const name)
+{
+	return dev->type == &disk_type
+			&& strcmp(name, dev_to_disk(dev)->disk_name) == 0;
+}
+
+/**
+ * get_disk_by_name - get a gendisk by name
+ * @name:	the name of the disk
+ *
+ * Returns a pointer to the gendisk named @name (if it exists), @NULL if not.
+ * Increments the disk's reference count, so caller must call put_device().
+ */
+struct gendisk *get_disk_by_name(const char *const name)
+{
+	struct device *dev;
+
+	dev = class_find_device(&block_class, NULL, name, match_disk_name);
+	if (dev == NULL)
+		return NULL;
+
+	return dev_to_disk(dev);
+}
+EXPORT_SYMBOL_GPL(get_disk_by_name);
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 13b34177cc85..b26bbf2d9048 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -342,4 +342,14 @@ static inline void printk_all_partitions(void)
 }
 #endif /* CONFIG_BLOCK */
 
+/* for blkdev LED trigger (drivers/leds/trigger/ledtrig-blkdev.c) */
+#ifdef CONFIG_BLOCK
+struct gendisk *get_disk_by_name(const char *name);
+#else
+static inline struct gendisk *get_disk_by_name(const char *name)
+{
+	return NULL;
+}
+#endif
+
 #endif /* _LINUX_GENHD_H */
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 03/18] ledtrig-blkdev: Add file (ledtrig-blkdev.c) for block device LED trigger
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 01/18] docs: Add block device (blkdev) LED trigger documentation Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 02/18] block: Add get_disk_by_name() for use by blkdev LED trigger Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 04/18] ledtrig-blkdev: Add misc. helper functions to blkdev " Ian Pilcher
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

Add data types and global variables

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 drivers/leds/trigger/ledtrig-blkdev.c | 66 +++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 drivers/leds/trigger/ledtrig-blkdev.c

diff --git a/drivers/leds/trigger/ledtrig-blkdev.c b/drivers/leds/trigger/ledtrig-blkdev.c
new file mode 100644
index 000000000000..28ccbd7946ba
--- /dev/null
+++ b/drivers/leds/trigger/ledtrig-blkdev.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ *	Block device LED triggers
+ *
+ *	Copyright 2021 Ian Pilcher <arequipeno@gmail.com>
+ */
+
+#include <linux/leds.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+
+/* Default blink time & polling interval (milliseconds) */
+#define LEDTRIG_BLKDEV_BLINK_MSEC	75
+#define LEDTRIG_BLKDEV_INTERVAL		100
+
+/* Minimum VALUE for interval or blink_time */
+#define LEDTRIG_BLKDEV_MIN_TIME		25
+
+enum ledtrig_blkdev_mode {
+	LEDTRIG_BLKDEV_MODE_RO	= 0,	/* blink for reads */
+	LEDTRIG_BLKDEV_MODE_WO	= 1,	/* blink for writes */
+	LEDTRIG_BLKDEV_MODE_RW	= 2	/* blink for reads and writes */
+};
+
+/* Trigger-specific info about a block device */
+struct ledtrig_blkdev_disk {
+	struct gendisk		*gd;
+	struct kobject		*dir;
+	struct hlist_head	leds;
+	unsigned long		read_ios;
+	unsigned long		write_ios;
+	unsigned int		generation;
+	bool			read_act;
+	bool			write_act;
+};
+
+/* For many-to-many relationships between "disks" (block devices) and LEDs */
+struct ledtrig_blkdev_link {
+	struct hlist_node		disk_leds_node;
+	struct hlist_node		led_disks_node;
+	struct ledtrig_blkdev_disk	*disk;
+	struct ledtrig_blkdev_led	*led;
+};
+
+/* Every LED associated with the blkdev trigger gets one of these */
+struct ledtrig_blkdev_led {
+	struct kobject			*dir;		/* block_devices dir */
+	struct led_classdev		*led_dev;
+	unsigned int			blink_msec;
+	struct hlist_head		disks;		/* linked block devs */
+	struct hlist_node		leds_node;
+	enum ledtrig_blkdev_mode	mode;
+};
+
+/* All LEDs associated with the trigger */
+static HLIST_HEAD(ledtrig_blkdev_leds);
+
+/* Must hold when changing trigger/LED/device associations */
+static DEFINE_MUTEX(ledtrig_blkdev_mutex);
+
+/* Total number of device-to-LED associations */
+static unsigned int ledtrig_blkdev_count;
+
+/* How often to check for drive activity - in jiffies */
+static unsigned int ledtrig_blkdev_interval;
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 04/18] ledtrig-blkdev: Add misc. helper functions to blkdev LED trigger
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
                   ` (2 preceding siblings ...)
  2021-08-19  2:50 ` [RFC PATCH v3 03/18] ledtrig-blkdev: Add file (ledtrig-blkdev.c) for block device " Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 05/18] ledtrig-blkdev: Periodically check devices for activity & blink LEDs Ian Pilcher
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

Add various helper functions to the block device LED trigger:

  * blkdev_mkdir() - create a sysfs directory (and don't swallow error
    codes)

  * blkdev_streq(), blkdev_skip_space() & blkdev_find_space() - for
    parsing writes to sysfs attributes

  * blkdev_read_mode() & blkdev_write_mode() - LED mode activity type
    helpers

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 drivers/leds/trigger/ledtrig-blkdev.c | 74 +++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)

diff --git a/drivers/leds/trigger/ledtrig-blkdev.c b/drivers/leds/trigger/ledtrig-blkdev.c
index 28ccbd7946ba..fcae7ce63b92 100644
--- a/drivers/leds/trigger/ledtrig-blkdev.c
+++ b/drivers/leds/trigger/ledtrig-blkdev.c
@@ -6,6 +6,7 @@
  *	Copyright 2021 Ian Pilcher <arequipeno@gmail.com>
  */
 
+#include <linux/ctype.h>
 #include <linux/leds.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
@@ -64,3 +65,76 @@ static unsigned int ledtrig_blkdev_count;
 
 /* How often to check for drive activity - in jiffies */
 static unsigned int ledtrig_blkdev_interval;
+
+
+/*
+ *
+ *	Miscellaneous helper functions
+ *
+ */
+
+/* Like kobject_create_and_add(), but doesn't swallow error codes */
+static struct kobject *blkdev_mkdir(const char *const name,
+				    struct kobject *const parent)
+{
+	struct kobject *dir;
+	int ret;
+
+	dir = kobject_create();
+	if (dir == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	ret = kobject_add(dir, parent, "%s", name);
+	if (ret != 0) {
+		kobject_put(dir);
+		return ERR_PTR(ret);
+	}
+
+	return dir;
+}
+
+/*
+ * Compare a null-terminated C string with a non-null-terminated character
+ * sequence of a known length.  Returns true if equal, false if not.
+ */
+static bool blkdev_streq(const char *const cstr,
+			 const char *const cbuf, const size_t buf_len)
+{
+	return (strlen(cstr) == buf_len) && (memcmp(cstr, cbuf, buf_len) == 0);
+}
+
+/*
+ * Returns a pointer to the first non-whitespace character in s
+ * (or a pointer to the terminating null).
+ */
+static const char *blkdev_skip_space(const char *s)
+{
+	while (*s != 0 && isspace(*s))
+		++s;
+
+	return s;
+}
+
+/*
+ * Returns a pointer to the first whitespace character in s (or a pointer to the
+ * terminating null), which is effectively a pointer to the position *after* the
+ * last character in the non-whitespace token at the beginning of s.  (s is
+ * expected to be the result of a previous call to blkdev_skip_space()).
+ */
+static const char *blkdev_find_space(const char *s)
+{
+	while (*s != 0 && !isspace(*s))
+		++s;
+
+	return s;
+}
+
+static bool blkdev_read_mode(const enum ledtrig_blkdev_mode mode)
+{
+	return mode != LEDTRIG_BLKDEV_MODE_WO;
+}
+
+static bool blkdev_write_mode(const enum ledtrig_blkdev_mode mode)
+{
+	return mode != LEDTRIG_BLKDEV_MODE_RO;
+}
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 05/18] ledtrig-blkdev: Periodically check devices for activity & blink LEDs
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
                   ` (3 preceding siblings ...)
  2021-08-19  2:50 ` [RFC PATCH v3 04/18] ledtrig-blkdev: Add misc. helper functions to blkdev " Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 06/18] block: Add LED trigger pointer to struct gendisk Ian Pilcher
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

Use a delayed workqueue to periodically check configured block devices for
activity since the last check.  Blink LEDs associated with devices on which
the configured type of activity (read/write) has occurred.

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 drivers/leds/trigger/ledtrig-blkdev.c | 87 +++++++++++++++++++++++++++
 1 file changed, 87 insertions(+)

diff --git a/drivers/leds/trigger/ledtrig-blkdev.c b/drivers/leds/trigger/ledtrig-blkdev.c
index fcae7ce63b92..e9c23824c33c 100644
--- a/drivers/leds/trigger/ledtrig-blkdev.c
+++ b/drivers/leds/trigger/ledtrig-blkdev.c
@@ -7,9 +7,11 @@
  */
 
 #include <linux/ctype.h>
+#include <linux/genhd.h>
 #include <linux/leds.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
+#include <linux/part_stat.h>
 
 /* Default blink time & polling interval (milliseconds) */
 #define LEDTRIG_BLKDEV_BLINK_MSEC	75
@@ -66,6 +68,9 @@ static unsigned int ledtrig_blkdev_count;
 /* How often to check for drive activity - in jiffies */
 static unsigned int ledtrig_blkdev_interval;
 
+static void blkdev_process(struct work_struct *const work);
+static DECLARE_DELAYED_WORK(ledtrig_blkdev_work, blkdev_process);
+
 
 /*
  *
@@ -138,3 +143,85 @@ static bool blkdev_write_mode(const enum ledtrig_blkdev_mode mode)
 {
 	return mode != LEDTRIG_BLKDEV_MODE_RO;
 }
+
+
+/*
+ *
+ *	Periodically check for device acitivity and blink LEDs
+ *
+ */
+
+static void blkdev_blink(const struct ledtrig_blkdev_led *const led)
+{
+	unsigned long delay_on = READ_ONCE(led->blink_msec);
+	unsigned long delay_off = 1;	/* 0 leaves LED turned on */
+
+	led_blink_set_oneshot(led->led_dev, &delay_on, &delay_off, 0);
+}
+
+static void blkdev_update_disk(struct ledtrig_blkdev_disk *const disk,
+			       const unsigned int generation)
+{
+	const struct block_device *const part0 = disk->gd->part0;
+	const unsigned long read_ios = part_stat_read(part0, ios[STAT_READ]);
+	const unsigned long write_ios = part_stat_read(part0, ios[STAT_WRITE])
+				+ part_stat_read(part0, ios[STAT_DISCARD])
+				+ part_stat_read(part0, ios[STAT_FLUSH]);
+
+	if (disk->read_ios != read_ios) {
+		disk->read_act = true;
+		disk->read_ios = read_ios;
+	} else {
+		disk->read_act = false;
+	}
+
+	if (disk->write_ios != write_ios) {
+		disk->write_act = true;
+		disk->write_ios = write_ios;
+	} else {
+		disk->write_act = false;
+	}
+
+	disk->generation = generation;
+}
+
+static void blkdev_process(struct work_struct *const work)
+{
+	static unsigned int generation;
+
+	struct ledtrig_blkdev_led *led;
+	struct ledtrig_blkdev_link *link;
+	unsigned long delay;
+
+	if (!mutex_trylock(&ledtrig_blkdev_mutex))
+		goto exit_reschedule;
+
+	hlist_for_each_entry(led, &ledtrig_blkdev_leds, leds_node) {
+
+		hlist_for_each_entry(link, &led->disks, led_disks_node) {
+
+			struct ledtrig_blkdev_disk *const disk = link->disk;
+
+			if (disk->generation != generation)
+				blkdev_update_disk(disk, generation);
+
+			if (disk->read_act && blkdev_read_mode(led->mode)) {
+				blkdev_blink(led);
+				break;
+			}
+
+			if (disk->write_act && blkdev_write_mode(led->mode)) {
+				blkdev_blink(led);
+				break;
+			}
+		}
+	}
+
+	++generation;
+
+	mutex_unlock(&ledtrig_blkdev_mutex);
+
+exit_reschedule:
+	delay = READ_ONCE(ledtrig_blkdev_interval);
+	WARN_ON_ONCE(!schedule_delayed_work(&ledtrig_blkdev_work, delay));
+}
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 06/18] block: Add LED trigger pointer to struct gendisk
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
                   ` (4 preceding siblings ...)
  2021-08-19  2:50 ` [RFC PATCH v3 05/18] ledtrig-blkdev: Periodically check devices for activity & blink LEDs Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 07/18] ledtrig-blkdev: Add function to initialize gendisk ledtrig member Ian Pilcher
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

Needed by ledtrig_blkdev_disk_cleanup(), which removes all monitoring of a
block device by the blkdev LED trigger when the device is removed

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 include/linux/genhd.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index b26bbf2d9048..66e2760702cb 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -168,6 +168,9 @@ struct gendisk {
 #endif	/* CONFIG_BLK_DEV_INTEGRITY */
 #if IS_ENABLED(CONFIG_CDROM)
 	struct cdrom_device_info *cdi;
+#endif
+#ifdef CONFIG_LEDS_TRIGGER_BLKDEV
+	struct ledtrig_blkdev_disk *ledtrig;
 #endif
 	int node_id;
 	struct badblocks *bb;
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 07/18] ledtrig-blkdev: Add function to initialize gendisk ledtrig member
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
                   ` (5 preceding siblings ...)
  2021-08-19  2:50 ` [RFC PATCH v3 06/18] block: Add LED trigger pointer to struct gendisk Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 08/18] ledtrig-blkdev: Add function to remove LED/device association Ian Pilcher
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

Ensures that gendisk ledtrig member is initialized to NULL, in case the
structure was not allocated with kzalloc() or equivalent

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 include/linux/leds.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/include/linux/leds.h b/include/linux/leds.h
index 329fd914cf24..6b67650d8797 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -10,6 +10,7 @@
 
 #include <dt-bindings/leds/common.h>
 #include <linux/device.h>
+#include <linux/genhd.h>
 #include <linux/kernfs.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
@@ -599,4 +600,19 @@ static inline void ledtrig_audio_set(enum led_audio type,
 }
 #endif
 
+#ifdef CONFIG_LEDS_TRIGGER_BLKDEV
+/**
+ * ledtrig_blkdev_disk_init - initialize the ledtrig field of a new gendisk
+ * @gd:	the gendisk to be initialized
+ */
+static inline void ledtrig_blkdev_disk_init(struct gendisk *const gd)
+{
+	gd->ledtrig = NULL;
+}
+#else	/* CONFIG_LEDS_TRIGGER_BLKDEV */
+static inline void ledtrig_blkdev_disk_init(const struct gendisk *gd)
+{
+}
+#endif	/* CONFIG_LEDS_TRIGGER_BLKDEV */
+
 #endif		/* __LINUX_LEDS_H_INCLUDED */
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 08/18] ledtrig-blkdev: Add function to remove LED/device association
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
                   ` (6 preceding siblings ...)
  2021-08-19  2:50 ` [RFC PATCH v3 07/18] ledtrig-blkdev: Add function to initialize gendisk ledtrig member Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 09/18] ledtrig-blkdev: Add function to disassociate a device from all LEDs Ian Pilcher
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

Remove symlinks in /sys/class/leds/<led>/block_devices and
/sys/block/<disk>/blkdev_leds

Decrement reference count on /sys/block/<disk>/blkdev_leds
directory (removes directory when empty)

Cancel delayed work when disassociating last device

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 drivers/leds/trigger/ledtrig-blkdev.c | 56 +++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/drivers/leds/trigger/ledtrig-blkdev.c b/drivers/leds/trigger/ledtrig-blkdev.c
index e9c23824c33c..447fc81ae0c5 100644
--- a/drivers/leds/trigger/ledtrig-blkdev.c
+++ b/drivers/leds/trigger/ledtrig-blkdev.c
@@ -225,3 +225,59 @@ static void blkdev_process(struct work_struct *const work)
 	delay = READ_ONCE(ledtrig_blkdev_interval);
 	WARN_ON_ONCE(!schedule_delayed_work(&ledtrig_blkdev_work, delay));
 }
+
+
+/*
+ *
+ *	Disassociate a block device from an LED
+ *
+ */
+
+static void blkdev_disk_del_locked(struct ledtrig_blkdev_led *const led,
+				   struct ledtrig_blkdev_link *const link,
+				   struct ledtrig_blkdev_disk *const disk)
+{
+	--ledtrig_blkdev_count;
+
+	if (ledtrig_blkdev_count == 0)
+		WARN_ON(!cancel_delayed_work_sync(&ledtrig_blkdev_work));
+
+	sysfs_remove_link(led->dir, disk->gd->disk_name);
+	sysfs_remove_link(disk->dir, led->led_dev->name);
+	kobject_put(disk->dir);
+
+	hlist_del(&link->led_disks_node);
+	hlist_del(&link->disk_leds_node);
+	kfree(link);
+
+	if (hlist_empty(&disk->leds)) {
+		disk->gd->ledtrig = NULL;
+		kfree(disk);
+	}
+
+	put_device(disk_to_dev(disk->gd));
+}
+
+static void blkdev_disk_delete(struct ledtrig_blkdev_led *const led,
+			       const char *const disk_name,
+			       const size_t name_len)
+{
+	struct ledtrig_blkdev_link *link;
+
+	mutex_lock(&ledtrig_blkdev_mutex);
+
+	hlist_for_each_entry(link, &led->disks, led_disks_node) {
+
+		if (blkdev_streq(link->disk->gd->disk_name,
+						disk_name, name_len)) {
+			blkdev_disk_del_locked(led, link, link->disk);
+			goto exit_unlock;
+		}
+	}
+
+	pr_info("blkdev LED: %.*s not associated with LED %s\n",
+		(int)name_len, disk_name, led->led_dev->name);
+
+exit_unlock:
+	mutex_unlock(&ledtrig_blkdev_mutex);
+}
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 09/18] ledtrig-blkdev: Add function to disassociate a device from all LEDs
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
                   ` (7 preceding siblings ...)
  2021-08-19  2:50 ` [RFC PATCH v3 08/18] ledtrig-blkdev: Add function to remove LED/device association Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 10/18] block: Call LED trigger init/cleanup functions Ian Pilcher
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

Called when block device is being removed

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 drivers/leds/trigger/ledtrig-blkdev.c | 31 +++++++++++++++++++++++++++
 include/linux/leds.h                  |  4 ++++
 2 files changed, 35 insertions(+)

diff --git a/drivers/leds/trigger/ledtrig-blkdev.c b/drivers/leds/trigger/ledtrig-blkdev.c
index 447fc81ae0c5..2072cc904616 100644
--- a/drivers/leds/trigger/ledtrig-blkdev.c
+++ b/drivers/leds/trigger/ledtrig-blkdev.c
@@ -281,3 +281,34 @@ static void blkdev_disk_delete(struct ledtrig_blkdev_led *const led,
 exit_unlock:
 	mutex_unlock(&ledtrig_blkdev_mutex);
 }
+
+
+/*
+ *
+ *	Disassociate all LEDs from a block device (because it's going away)
+ *
+ */
+
+/**
+ * ledtrig_blkdev_disk_cleanup - remove a block device from the blkdev LED
+ * trigger
+ * @disk:	the disk to be removed
+ */
+void ledtrig_blkdev_disk_cleanup(struct gendisk *const gd)
+{
+	struct ledtrig_blkdev_link *link;
+	struct hlist_node *next;
+
+	mutex_lock(&ledtrig_blkdev_mutex);
+
+	if (gd->ledtrig != NULL) {
+
+		hlist_for_each_entry_safe(link, next,
+					  &gd->ledtrig->leds, disk_leds_node) {
+			blkdev_disk_del_locked(link->led, link, gd->ledtrig);
+		}
+	}
+
+	mutex_unlock(&ledtrig_blkdev_mutex);
+}
+EXPORT_SYMBOL_GPL(ledtrig_blkdev_disk_cleanup);
diff --git a/include/linux/leds.h b/include/linux/leds.h
index 6b67650d8797..98c479814988 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -609,10 +609,14 @@ static inline void ledtrig_blkdev_disk_init(struct gendisk *const gd)
 {
 	gd->ledtrig = NULL;
 }
+void ledtrig_blkdev_disk_cleanup(struct gendisk *const gd);
 #else	/* CONFIG_LEDS_TRIGGER_BLKDEV */
 static inline void ledtrig_blkdev_disk_init(const struct gendisk *gd)
 {
 }
+static inline void ledtrig_blkdev_disk_cleanup(const struct gendisk *gd)
+{
+}
 #endif	/* CONFIG_LEDS_TRIGGER_BLKDEV */
 
 #endif		/* __LINUX_LEDS_H_INCLUDED */
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 10/18] block: Call LED trigger init/cleanup functions
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
                   ` (8 preceding siblings ...)
  2021-08-19  2:50 ` [RFC PATCH v3 09/18] ledtrig-blkdev: Add function to disassociate a device from all LEDs Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 11/18] ledtrig-blkdev: Add function to associate a device with an LED Ian Pilcher
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

Call ledtrig_blkdev_disk_init() from __device_add_disk() to ensure that
gendisk's ledtrig field is initialized

Call ledtrig_blkdev_disk_cleanup() from del_gendisk() to clean up any
references to the device from the block device LED trigger

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 block/genhd.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/block/genhd.c b/block/genhd.c
index e6d7bb709d62..091b954ddab3 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -24,6 +24,7 @@
 #include <linux/log2.h>
 #include <linux/pm_runtime.h>
 #include <linux/badblocks.h>
+#include <linux/leds.h>
 
 #include "blk.h"
 
@@ -539,6 +540,7 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk,
 
 	disk_add_events(disk);
 	blk_integrity_add(disk);
+	ledtrig_blkdev_disk_init(disk);
 }
 
 void device_add_disk(struct device *parent, struct gendisk *disk,
@@ -581,6 +583,7 @@ void del_gendisk(struct gendisk *disk)
 	if (WARN_ON_ONCE(!disk->queue))
 		return;
 
+	ledtrig_blkdev_disk_cleanup(disk);
 	blk_integrity_del(disk);
 	disk_del_events(disk);
 
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 11/18] ledtrig-blkdev: Add function to associate a device with an LED
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
                   ` (9 preceding siblings ...)
  2021-08-19  2:50 ` [RFC PATCH v3 10/18] block: Call LED trigger init/cleanup functions Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 12/18] ledtrig-blkdev: Add sysfs attributes to [dis]associate LEDs & devices Ian Pilcher
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

If this is the first LED associated with the device, create the
/sys/block/<disk>/blkdev_leds directory.  Otherwise, increment its
reference count.

Create symlinks in /sys/class/leds/<led>/block_devices and
/sys/block/<disk>/blkdev_leds

If this the first device associated with any LED, schedule delayed work
to periodically check associated devices and blink LEDs

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 drivers/leds/trigger/ledtrig-blkdev.c | 168 ++++++++++++++++++++++++++
 1 file changed, 168 insertions(+)

diff --git a/drivers/leds/trigger/ledtrig-blkdev.c b/drivers/leds/trigger/ledtrig-blkdev.c
index 2072cc904616..a1646752b9a0 100644
--- a/drivers/leds/trigger/ledtrig-blkdev.c
+++ b/drivers/leds/trigger/ledtrig-blkdev.c
@@ -312,3 +312,171 @@ void ledtrig_blkdev_disk_cleanup(struct gendisk *const gd)
 	mutex_unlock(&ledtrig_blkdev_mutex);
 }
 EXPORT_SYMBOL_GPL(ledtrig_blkdev_disk_cleanup);
+
+
+/*
+ *
+ *	Associate a block device with an LED
+ *
+ */
+
+/* Gets or allocs & initializes the blkdev disk for a gendisk */
+static int blkdev_get_disk(struct gendisk *const gd)
+{
+	struct ledtrig_blkdev_disk *disk;
+	struct kobject *dir;
+
+	if (gd->ledtrig != NULL) {
+		kobject_get(gd->ledtrig->dir);
+		return 0;
+	}
+
+	disk = kmalloc(sizeof(*disk), GFP_KERNEL);
+	if (disk == NULL)
+		return -ENOMEM;
+
+	dir = blkdev_mkdir("blkdev_leds", &disk_to_dev(gd)->kobj);
+	if (IS_ERR(dir)) {
+		kfree(disk);
+		return PTR_ERR(dir);
+	}
+
+	INIT_HLIST_HEAD(&disk->leds);
+	disk->gd = gd;
+	disk->dir = dir;
+	disk->read_ios = 0;
+	disk->write_ios = 0;
+
+	gd->ledtrig = disk;
+
+	return 0;
+}
+
+static void blkdev_put_disk(struct ledtrig_blkdev_disk *const disk)
+{
+	kobject_put(disk->dir);
+
+	if (hlist_empty(&disk->leds)) {
+		disk->gd->ledtrig = NULL;
+		kfree(disk);
+	}
+}
+
+static int blkdev_disk_add_locked(struct ledtrig_blkdev_led *const led,
+				  struct gendisk *const gd)
+{
+	struct ledtrig_blkdev_link *link;
+	struct ledtrig_blkdev_disk *disk;
+	unsigned long delay;
+	int ret;
+
+	link = kmalloc(sizeof(*link), GFP_KERNEL);
+	if (link == NULL) {
+		ret = -ENOMEM;
+		goto error_return;
+	}
+
+	ret = blkdev_get_disk(gd);
+	if (ret != 0)
+		goto error_free_link;
+
+	disk = gd->ledtrig;
+
+	ret = sysfs_create_link(disk->dir, &led->led_dev->dev->kobj,
+				led->led_dev->name);
+	if (ret != 0)
+		goto error_put_disk;
+
+	ret = sysfs_create_link(led->dir, &disk_to_dev(gd)->kobj,
+				gd->disk_name);
+	if (ret != 0)
+		goto error_remove_link;
+
+	link->disk = disk;
+	link->led = led;
+	hlist_add_head(&link->led_disks_node, &led->disks);
+	hlist_add_head(&link->disk_leds_node, &disk->leds);
+
+	if (ledtrig_blkdev_count == 0) {
+		delay = READ_ONCE(ledtrig_blkdev_interval);
+		WARN_ON(!schedule_delayed_work(&ledtrig_blkdev_work, delay));
+	}
+
+	++ledtrig_blkdev_count;
+
+	return 0;
+
+error_remove_link:
+	sysfs_remove_link(disk->dir, led->led_dev->name);
+error_put_disk:
+	blkdev_put_disk(disk);
+error_free_link:
+	kfree(link);
+error_return:
+	return ret;
+}
+
+static bool blkdev_already_linked(const struct ledtrig_blkdev_led *const led,
+				  const struct gendisk *const gd)
+{
+	const struct ledtrig_blkdev_link *link;
+
+	if (gd->ledtrig == NULL)
+		return false;
+
+	hlist_for_each_entry(link, &gd->ledtrig->leds, disk_leds_node) {
+
+		if (link->led == led) {
+			pr_info("blkdev LED: %s already associated with %s\n",
+				gd->disk_name, led->led_dev->name);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+static int blkdev_disk_add(struct ledtrig_blkdev_led *const led,
+			   const char *const disk_name, const size_t name_len)
+{
+	static char name[DISK_NAME_LEN];	/* only used w/ mutex locked */
+	struct gendisk *gd;
+	int ret;
+
+	if (name_len >= DISK_NAME_LEN) {
+		pr_info("blkdev LED: invalid device name %.*s\n",
+			(int)name_len, disk_name);
+		ret = -EINVAL;
+		goto exit_return;
+	}
+
+	ret = mutex_lock_interruptible(&ledtrig_blkdev_mutex);
+	if (ret != 0)
+		goto exit_return;
+
+	memcpy(name, disk_name, name_len);
+	name[name_len] = 0;
+	gd = get_disk_by_name(name);	/* increments disk's refcount */
+
+	if (gd == NULL) {
+		pr_info("blkdev LED: no such block device %.*s\n",
+			(int)name_len, disk_name);
+		ret = -ENODEV;
+		goto exit_unlock;
+	}
+
+	if (blkdev_already_linked(led, gd)) {
+		ret = -EEXIST;
+		goto exit_put_dev;
+	}
+
+	ret = blkdev_disk_add_locked(led, gd);
+
+exit_put_dev:
+	if (ret != 0)
+		put_device(disk_to_dev(gd));
+exit_unlock:
+	mutex_unlock(&ledtrig_blkdev_mutex);
+exit_return:
+	return ret;
+}
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 12/18] ledtrig-blkdev: Add sysfs attributes to [dis]associate LEDs & devices
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
                   ` (10 preceding siblings ...)
  2021-08-19  2:50 ` [RFC PATCH v3 11/18] ledtrig-blkdev: Add function to associate a device with an LED Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 13/18] ledtrig-blkdev: Add blink_time & interval sysfs attributes Ian Pilcher
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

/sys/class/leds/<led>/add_blkdev - to create device/LED associations

/sys/class/leds/<led>/delete_blkdev to remove device/LED associations

For both attributes, accept multiple device names separated by whitespace

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 drivers/leds/trigger/ledtrig-blkdev.c | 48 +++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/drivers/leds/trigger/ledtrig-blkdev.c b/drivers/leds/trigger/ledtrig-blkdev.c
index a1646752b9a0..15b15aefdfd8 100644
--- a/drivers/leds/trigger/ledtrig-blkdev.c
+++ b/drivers/leds/trigger/ledtrig-blkdev.c
@@ -480,3 +480,51 @@ static int blkdev_disk_add(struct ledtrig_blkdev_led *const led,
 exit_return:
 	return ret;
 }
+
+
+/*
+ *
+ *	sysfs attributes to add & delete devices from LEDs
+ *
+ */
+
+static ssize_t blkdev_add_or_del(struct device *const dev,
+				 struct device_attribute *const attr,
+				 const char *const buf, const size_t count);
+
+static struct device_attribute ledtrig_blkdev_attr_add =
+	__ATTR(add_blkdev, 0200, NULL, blkdev_add_or_del);
+
+static struct device_attribute ledtrig_blkdev_attr_del =
+	__ATTR(delete_blkdev, 0200, NULL, blkdev_add_or_del);
+
+static ssize_t blkdev_add_or_del(struct device *const dev,
+				 struct device_attribute *const attr,
+				 const char *const buf, const size_t count)
+{
+	struct ledtrig_blkdev_led *const led = led_trigger_get_drvdata(dev);
+	const char *const disk_name = blkdev_skip_space(buf);
+	const char *const endp = blkdev_find_space(disk_name);
+	const ptrdiff_t name_len = endp - disk_name;	/* always >= 0 */
+	int ret;
+
+	if (name_len == 0) {
+		pr_info("blkdev LED: empty block device name\n");
+		return -EINVAL;
+	}
+
+	if (attr == &ledtrig_blkdev_attr_del) {
+		blkdev_disk_delete(led, disk_name, name_len);
+	} else {	/* attr == &ledtrig_blkdev_attr_add */
+		ret = blkdev_disk_add(led, disk_name, name_len);
+		if (ret != 0)
+			return ret;
+	}
+
+	/*
+	 * Consume everything up to the next non-whitespace token (or the end
+	 * of the input).  Avoids "empty block device name" error if there is
+	 * whitespace after the last token (e.g. a newline).
+	 */
+	return blkdev_skip_space(endp) - buf;
+}
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 13/18] ledtrig-blkdev: Add blink_time & interval sysfs attributes
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
                   ` (11 preceding siblings ...)
  2021-08-19  2:50 ` [RFC PATCH v3 12/18] ledtrig-blkdev: Add sysfs attributes to [dis]associate LEDs & devices Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 14/18] ledtrig-blkdev: Add mode (read/write/rw) sysfs attributue Ian Pilcher
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

/sys/class/leds/<led>/blink_time controls - per-LED blink duration

/sys/class/leds/<led>/interval - global frequency with which devices
are checked for activity and LEDs are blinked

Enforce 25 millisecond minimum for both attributes

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 drivers/leds/trigger/ledtrig-blkdev.c | 63 +++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/drivers/leds/trigger/ledtrig-blkdev.c b/drivers/leds/trigger/ledtrig-blkdev.c
index 15b15aefdfd8..481b2d142db2 100644
--- a/drivers/leds/trigger/ledtrig-blkdev.c
+++ b/drivers/leds/trigger/ledtrig-blkdev.c
@@ -528,3 +528,66 @@ static ssize_t blkdev_add_or_del(struct device *const dev,
 	 */
 	return blkdev_skip_space(endp) - buf;
 }
+
+
+/*
+ *
+ *	blink_time & interval device attributes
+ *
+ */
+
+static ssize_t blkdev_time_show(struct device *const dev,
+				      struct device_attribute *const attr,
+				      char *const buf);
+
+static ssize_t blkdev_time_store(struct device *const dev,
+				 struct device_attribute *const attr,
+				 const char *const buf, const size_t count);
+
+static struct device_attribute ledtrig_blkdev_attr_blink_time =
+	__ATTR(blink_time, 0644, blkdev_time_show, blkdev_time_store);
+
+static struct device_attribute ledtrig_blkdev_attr_interval =
+	__ATTR(interval, 0644, blkdev_time_show, blkdev_time_store);
+
+static ssize_t blkdev_time_show(struct device *const dev,
+				struct device_attribute *const attr,
+				char *const buf)
+{
+	const struct ledtrig_blkdev_led *const led =
+						led_trigger_get_drvdata(dev);
+	unsigned int value;
+
+	if (attr == &ledtrig_blkdev_attr_blink_time)
+		value = READ_ONCE(led->blink_msec);
+	else	// attr == &ledtrig_blkdev_attr_interval
+		value = jiffies_to_msecs(READ_ONCE(ledtrig_blkdev_interval));
+
+	return sprintf(buf, "%u\n", value);
+}
+
+static ssize_t blkdev_time_store(struct device *const dev,
+				 struct device_attribute *const attr,
+				 const char *const buf, const size_t count)
+{
+	struct ledtrig_blkdev_led *const led = led_trigger_get_drvdata(dev);
+	unsigned int value;
+	int ret;
+
+	ret = kstrtouint(buf, 0, &value);
+	if (ret != 0)
+		return ret;
+
+	if (value < LEDTRIG_BLKDEV_MIN_TIME) {
+		pr_info("blkdev LED: attempt to set time < %s milliseconds\n",
+			__stringify(LEDTRIG_BLKDEV_MIN_TIME));
+		return -ERANGE;
+	}
+
+	if (attr == &ledtrig_blkdev_attr_blink_time)
+		WRITE_ONCE(led->blink_msec, value);
+	else	// attr == &ledtrig_blkdev_attr_interval
+		WRITE_ONCE(ledtrig_blkdev_interval, msecs_to_jiffies(value));
+
+	return count;
+}
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 14/18] ledtrig-blkdev: Add mode (read/write/rw) sysfs attributue
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
                   ` (12 preceding siblings ...)
  2021-08-19  2:50 ` [RFC PATCH v3 13/18] ledtrig-blkdev: Add blink_time & interval sysfs attributes Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 15/18] ledtrig-blkdev: Add function to associate blkdev trigger with LED Ian Pilcher
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

Show all modes, with current mode in square brackets, in show function

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 drivers/leds/trigger/ledtrig-blkdev.c | 67 +++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/drivers/leds/trigger/ledtrig-blkdev.c b/drivers/leds/trigger/ledtrig-blkdev.c
index 481b2d142db2..88e2a11af1a9 100644
--- a/drivers/leds/trigger/ledtrig-blkdev.c
+++ b/drivers/leds/trigger/ledtrig-blkdev.c
@@ -591,3 +591,70 @@ static ssize_t blkdev_time_store(struct device *const dev,
 
 	return count;
 }
+
+
+/*
+ *
+ *	LED mode device attribute
+ *
+ */
+
+static const struct {
+	const char	*name;
+	const char	*show;
+} blkdev_modes[] = {
+	[LEDTRIG_BLKDEV_MODE_RO] = {
+		.name	= "read",
+		.show	= "[read] write rw\n",
+	},
+	[LEDTRIG_BLKDEV_MODE_WO] = {
+		.name	= "write",
+		.show	= "read [write] rw\n",
+	},
+	[LEDTRIG_BLKDEV_MODE_RW] = {
+		.name	= "rw",
+		.show	= "read write [rw]\n",
+	},
+};
+
+static ssize_t blkdev_mode_show(struct device *const dev,
+				struct device_attribute *const attr,
+				char *const buf)
+{
+	const struct ledtrig_blkdev_led *const led =
+					led_trigger_get_drvdata(dev);
+
+	return sprintf(buf, blkdev_modes[READ_ONCE(led->mode)].show);
+}
+
+static ssize_t blkdev_mode_store(struct device *const dev,
+				 struct device_attribute *const attr,
+				 const char *const buf, const size_t count)
+{
+	struct ledtrig_blkdev_led *const led = led_trigger_get_drvdata(dev);
+	const char *const mode_name = blkdev_skip_space(buf);
+	const char *const endp = blkdev_find_space(mode_name);
+	const ptrdiff_t name_len = endp - mode_name;	/* always >= 0 */
+	enum ledtrig_blkdev_mode mode;
+
+	if (name_len == 0) {
+		pr_info("blkdev LED: empty mode\n");
+		return -EINVAL;
+	}
+
+	for (mode = LEDTRIG_BLKDEV_MODE_RO;
+				mode <= LEDTRIG_BLKDEV_MODE_RW; ++mode) {
+
+		if (blkdev_streq(blkdev_modes[mode].name,
+						mode_name, name_len)) {
+			WRITE_ONCE(led->mode, mode);
+			return count;
+		}
+	}
+
+	pr_info("blkdev LED: invalid mode (%.*s)\n", (int)name_len, mode_name);
+	return -EINVAL;
+}
+
+static struct device_attribute ledtrig_blkdev_attr_mode =
+	__ATTR(mode, 0644, blkdev_mode_show, blkdev_mode_store);
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 15/18] ledtrig-blkdev: Add function to associate blkdev trigger with LED
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
                   ` (13 preceding siblings ...)
  2021-08-19  2:50 ` [RFC PATCH v3 14/18] ledtrig-blkdev: Add mode (read/write/rw) sysfs attributue Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 16/18] ledtrig-blkdev: Add function to disassociate an LED from the trigger Ian Pilcher
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

Allocate per-LED data structure and initialize with default values

Create /sys/class/leds/<led>/block_devices directory

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 drivers/leds/trigger/ledtrig-blkdev.c | 46 +++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/drivers/leds/trigger/ledtrig-blkdev.c b/drivers/leds/trigger/ledtrig-blkdev.c
index 88e2a11af1a9..b331e3f24b04 100644
--- a/drivers/leds/trigger/ledtrig-blkdev.c
+++ b/drivers/leds/trigger/ledtrig-blkdev.c
@@ -658,3 +658,49 @@ static ssize_t blkdev_mode_store(struct device *const dev,
 
 static struct device_attribute ledtrig_blkdev_attr_mode =
 	__ATTR(mode, 0644, blkdev_mode_show, blkdev_mode_store);
+
+
+/*
+ *
+ *	Associate an LED with the blkdev trigger
+ *
+ */
+
+static int blkdev_activate(struct led_classdev *const led_dev)
+{
+	struct ledtrig_blkdev_led *led;
+	int ret;
+
+	led = kmalloc(sizeof(*led), GFP_KERNEL);
+	if (led == NULL) {
+		ret = -ENOMEM;
+		goto exit_return;
+	}
+
+	led->led_dev = led_dev;
+	led->blink_msec = LEDTRIG_BLKDEV_BLINK_MSEC;
+	led->mode = LEDTRIG_BLKDEV_MODE_RW;
+	INIT_HLIST_HEAD(&led->disks);
+
+	ret = mutex_lock_interruptible(&ledtrig_blkdev_mutex);
+	if (ret != 0)
+		goto exit_free;
+
+	led->dir = blkdev_mkdir("block_devices", &led_dev->dev->kobj);
+	if (IS_ERR(led->dir)) {
+		ret = PTR_ERR(led->dir);
+		goto exit_unlock;
+	}
+
+	hlist_add_head(&led->leds_node, &ledtrig_blkdev_leds);
+	led_set_trigger_data(led_dev, led);
+	ret = 0;
+
+exit_unlock:
+	mutex_unlock(&ledtrig_blkdev_mutex);
+exit_free:
+	if (ret != 0)
+		kfree(led);
+exit_return:
+	return ret;
+}
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 16/18] ledtrig-blkdev: Add function to disassociate an LED from the trigger
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
                   ` (14 preceding siblings ...)
  2021-08-19  2:50 ` [RFC PATCH v3 15/18] ledtrig-blkdev: Add function to associate blkdev trigger with LED Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 17/18] ledtrig-blkdev: Add initialization function Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 18/18] ledtrig-blkdev: Add config option to enable the trigger Ian Pilcher
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

Remove all device associations with this LED

Remove /sys/class/leds/<led>/block_devices directory

Free per-LED data structure

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 drivers/leds/trigger/ledtrig-blkdev.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/leds/trigger/ledtrig-blkdev.c b/drivers/leds/trigger/ledtrig-blkdev.c
index b331e3f24b04..01573c1ad855 100644
--- a/drivers/leds/trigger/ledtrig-blkdev.c
+++ b/drivers/leds/trigger/ledtrig-blkdev.c
@@ -704,3 +704,28 @@ static int blkdev_activate(struct led_classdev *const led_dev)
 exit_return:
 	return ret;
 }
+
+
+/*
+ *
+ *	Disassociate an LED from the trigger
+ *
+ */
+
+static void blkdev_deactivate(struct led_classdev *const led_dev)
+{
+	struct ledtrig_blkdev_led *const led = led_get_trigger_data(led_dev);
+	struct ledtrig_blkdev_link *link;
+	struct hlist_node *next;
+
+	mutex_lock(&ledtrig_blkdev_mutex);
+
+	hlist_for_each_entry_safe(link, next, &led->disks, led_disks_node)
+		blkdev_disk_del_locked(led, link, link->disk);
+
+	hlist_del(&led->leds_node);
+	kobject_put(led->dir);
+	kfree(led);
+
+	mutex_unlock(&ledtrig_blkdev_mutex);
+}
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 17/18] ledtrig-blkdev: Add initialization function
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
                   ` (15 preceding siblings ...)
  2021-08-19  2:50 ` [RFC PATCH v3 16/18] ledtrig-blkdev: Add function to disassociate an LED from the trigger Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  2021-08-19  2:50 ` [RFC PATCH v3 18/18] ledtrig-blkdev: Add config option to enable the trigger Ian Pilcher
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

Register the block device LED trigger

Initialize interval (convert default value to jiffies)

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 drivers/leds/trigger/ledtrig-blkdev.c | 39 +++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/drivers/leds/trigger/ledtrig-blkdev.c b/drivers/leds/trigger/ledtrig-blkdev.c
index 01573c1ad855..f152b00a4f1a 100644
--- a/drivers/leds/trigger/ledtrig-blkdev.c
+++ b/drivers/leds/trigger/ledtrig-blkdev.c
@@ -729,3 +729,42 @@ static void blkdev_deactivate(struct led_classdev *const led_dev)
 
 	mutex_unlock(&ledtrig_blkdev_mutex);
 }
+
+
+/*
+ *
+ *	Initialization - register the trigger
+ *
+ */
+
+static struct attribute *ledtrig_blkdev_attrs[] = {
+	&ledtrig_blkdev_attr_add.attr,
+	&ledtrig_blkdev_attr_del.attr,
+	&ledtrig_blkdev_attr_blink_time.attr,
+	&ledtrig_blkdev_attr_interval.attr,
+	&ledtrig_blkdev_attr_mode.attr,
+	NULL
+};
+
+static const struct attribute_group ledtrig_blkdev_attr_group = {
+	.attrs	= ledtrig_blkdev_attrs,
+};
+
+static const struct attribute_group *ledtrig_blkdev_attr_groups[] = {
+	&ledtrig_blkdev_attr_group,
+	NULL
+};
+
+static struct led_trigger ledtrig_blkdev_trigger = {
+	.name		= "blkdev",
+	.activate	= blkdev_activate,
+	.deactivate	= blkdev_deactivate,
+	.groups		= ledtrig_blkdev_attr_groups,
+};
+
+static int __init blkdev_init(void)
+{
+	ledtrig_blkdev_interval = msecs_to_jiffies(LEDTRIG_BLKDEV_INTERVAL);
+	return led_trigger_register(&ledtrig_blkdev_trigger);
+}
+device_initcall(blkdev_init);
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [RFC PATCH v3 18/18] ledtrig-blkdev: Add config option to enable the trigger
  2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
                   ` (16 preceding siblings ...)
  2021-08-19  2:50 ` [RFC PATCH v3 17/18] ledtrig-blkdev: Add initialization function Ian Pilcher
@ 2021-08-19  2:50 ` Ian Pilcher
  17 siblings, 0 replies; 19+ messages in thread
From: Ian Pilcher @ 2021-08-19  2:50 UTC (permalink / raw)
  To: linux-block, linux-leds; +Cc: axboe, pavel, kabel, linux-kernel, kernelnewbies

Signed-off-by: Ian Pilcher <arequipeno@gmail.com>
---
 drivers/leds/trigger/Kconfig  | 9 +++++++++
 drivers/leds/trigger/Makefile | 1 +
 2 files changed, 10 insertions(+)

diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig
index b77a01bd27f4..f15d38b3a632 100644
--- a/drivers/leds/trigger/Kconfig
+++ b/drivers/leds/trigger/Kconfig
@@ -153,4 +153,13 @@ config LEDS_TRIGGER_TTY
 
 	  When build as a module this driver will be called ledtrig-tty.
 
+config LEDS_TRIGGER_BLKDEV
+	bool "LED Trigger for block devices"
+	depends on BLOCK
+	help
+	  The blkdev LED trigger allows LEDs to be controlled by block device
+	  activity (reads and writes).
+
+	  See Documentation/leds/ledtrig-blkdev.rst.
+
 endif # LEDS_TRIGGERS
diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile
index 25c4db97cdd4..d53bab5d93f1 100644
--- a/drivers/leds/trigger/Makefile
+++ b/drivers/leds/trigger/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_LEDS_TRIGGER_NETDEV)	+= ledtrig-netdev.o
 obj-$(CONFIG_LEDS_TRIGGER_PATTERN)	+= ledtrig-pattern.o
 obj-$(CONFIG_LEDS_TRIGGER_AUDIO)	+= ledtrig-audio.o
 obj-$(CONFIG_LEDS_TRIGGER_TTY)		+= ledtrig-tty.o
+obj-$(CONFIG_LEDS_TRIGGER_BLKDEV)	+= ledtrig-blkdev.o
-- 
2.31.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2021-08-19  2:51 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-19  2:50 [RFC PATCH v3 00/18] Add block device LED trigger Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 01/18] docs: Add block device (blkdev) LED trigger documentation Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 02/18] block: Add get_disk_by_name() for use by blkdev LED trigger Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 03/18] ledtrig-blkdev: Add file (ledtrig-blkdev.c) for block device " Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 04/18] ledtrig-blkdev: Add misc. helper functions to blkdev " Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 05/18] ledtrig-blkdev: Periodically check devices for activity & blink LEDs Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 06/18] block: Add LED trigger pointer to struct gendisk Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 07/18] ledtrig-blkdev: Add function to initialize gendisk ledtrig member Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 08/18] ledtrig-blkdev: Add function to remove LED/device association Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 09/18] ledtrig-blkdev: Add function to disassociate a device from all LEDs Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 10/18] block: Call LED trigger init/cleanup functions Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 11/18] ledtrig-blkdev: Add function to associate a device with an LED Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 12/18] ledtrig-blkdev: Add sysfs attributes to [dis]associate LEDs & devices Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 13/18] ledtrig-blkdev: Add blink_time & interval sysfs attributes Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 14/18] ledtrig-blkdev: Add mode (read/write/rw) sysfs attributue Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 15/18] ledtrig-blkdev: Add function to associate blkdev trigger with LED Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 16/18] ledtrig-blkdev: Add function to disassociate an LED from the trigger Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 17/18] ledtrig-blkdev: Add initialization function Ian Pilcher
2021-08-19  2:50 ` [RFC PATCH v3 18/18] ledtrig-blkdev: Add config option to enable the trigger Ian Pilcher

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).