All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ian Pilcher <arequipeno@gmail.com>
To: axboe@kernel.dk, pavel@ucw.cz
Cc: linux-leds@vger.kernel.org, linux-block@vger.kernel.org,
	linux@vger.kernel.org, gregkh@linuxfoundation.org,
	kabel@kernel.org
Subject: [PATCH 11/18] ledtrig-blkdev: Add function to associate a device with an LED
Date: Fri,  3 Sep 2021 15:45:41 -0500	[thread overview]
Message-ID: <20210903204548.2745354-12-arequipeno@gmail.com> (raw)
In-Reply-To: <20210903204548.2745354-1-arequipeno@gmail.com>

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 | 157 ++++++++++++++++++++++++++
 1 file changed, 157 insertions(+)

diff --git a/drivers/leds/trigger/ledtrig-blkdev.c b/drivers/leds/trigger/ledtrig-blkdev.c
index bbf71ff18057..e3169d1f0e38 100644
--- a/drivers/leds/trigger/ledtrig-blkdev.c
+++ b/drivers/leds/trigger/ledtrig-blkdev.c
@@ -252,3 +252,160 @@ static int blkdev_activate(struct led_classdev *const led_dev)
 exit_return:
 	return ret;
 }
+
+
+/*
+ *
+ *	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 = kobject_create_and_add("blkdev_leds", &disk_to_dev(gd)->kobj);
+	if (dir == NULL) {
+		kfree(disk);
+		return -ENOMEM;
+	}
+
+	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)
+{
+	struct gendisk *gd;
+	int ret;
+
+	ret = mutex_lock_interruptible(&ledtrig_blkdev_mutex);
+	if (ret != 0)
+		goto exit_return;
+
+	gd = ledtrig_blkdev_get_disk(disk_name, name_len);
+	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_disk;
+	}
+
+	ret = blkdev_disk_add_locked(led, gd);
+
+exit_put_disk:
+	if (ret != 0)
+		put_disk(gd);
+exit_unlock:
+	mutex_unlock(&ledtrig_blkdev_mutex);
+exit_return:
+	return ret;
+}
-- 
2.31.1


  parent reply	other threads:[~2021-09-03 20:46 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-09-03 20:45 [PATCH 00/18] Introduce block device LED trigger Ian Pilcher
2021-09-03 20:45 ` [PATCH 01/18] docs: Add block device (blkdev) LED trigger documentation Ian Pilcher
2021-09-04  6:29   ` Pavel Machek
2021-09-05 14:49     ` Ian Pilcher
2021-09-05 18:42       ` Pavel Machek
2021-09-05 23:13         ` Ian Pilcher
2021-09-03 20:45 ` [PATCH 02/18] ledtrig-blkdev: Add build infra for block device LED trigger Ian Pilcher
2021-09-03 20:45 ` [PATCH 03/18] ledtrig-blkdev: Add function placeholders needed by block changes Ian Pilcher
2021-09-04 16:57   ` kernel test robot
2021-09-04 16:57     ` kernel test robot
2021-09-03 20:45 ` [PATCH 04/18] block: Add block device LED trigger integrations Ian Pilcher
2021-09-03 20:45 ` [PATCH 05/18] ledtrig-blkdev: Implement functions called from block subsystem Ian Pilcher
2021-09-03 20:45 ` [PATCH 06/18] ledtrig-blkdev: Add function to get gendisk by name Ian Pilcher
2021-09-03 20:45 ` [PATCH 07/18] ledtrig-blkdev: Add constants, data types, and global variables Ian Pilcher
2021-09-03 20:45 ` [PATCH 08/18] ledtrig-blkdev: Add miscellaneous helper functions Ian Pilcher
2021-09-04  6:00   ` Greg KH
2021-09-04 22:43     ` Ian Pilcher
2021-09-03 20:45 ` [PATCH 09/18] ledtrig-blkdev: Periodically check devices for activity & blink LEDs Ian Pilcher
2021-09-04  6:01   ` Greg KH
2021-09-05 14:39     ` Ian Pilcher
2021-09-05 14:51       ` Greg KH
2021-09-05 14:56         ` Ian Pilcher
2021-09-05 15:12           ` Greg KH
2021-09-05 16:55             ` Eric Biggers
2021-09-03 20:45 ` [PATCH 10/18] ledtrig-blkdev: Add function to associate the trigger with an LED Ian Pilcher
2021-09-03 20:45 ` Ian Pilcher [this message]
2021-09-03 20:45 ` [PATCH 12/18] ledtrig-blkdev: Add function to remove LED/device association Ian Pilcher
2021-09-03 20:45 ` [PATCH 13/18] ledtrig-blkdev: Add function to disassociate a device from all LEDs Ian Pilcher
2021-09-03 20:45 ` [PATCH 14/18] ledtrig-blkdev: Add function to disassociate an LED from the trigger Ian Pilcher
2021-09-03 20:45 ` [PATCH 15/18] ledtrig-blkdev: Add sysfs attributes to [un]link LEDs & devices Ian Pilcher
2021-09-04  5:57   ` Greg KH
2021-09-04 21:28     ` Ian Pilcher
2021-09-04  5:59   ` Greg KH
2021-09-04 22:35     ` Ian Pilcher
2021-09-05 14:51       ` Greg KH
2021-09-05 15:33         ` Ian Pilcher
2021-09-05 16:43           ` Greg KH
2021-09-03 20:45 ` [PATCH 16/18] ledtrig-blkdev: Add blink_time & interval sysfs attributes Ian Pilcher
2021-09-03 20:45 ` [PATCH 17/18] ledtrig-blkdev: Add mode (read/write/rw) sysfs attributue Ian Pilcher
2021-09-04  5:57   ` Greg KH
2021-09-04 21:01     ` Ian Pilcher
2021-09-05 14:50       ` Greg KH
2021-09-03 20:45 ` [PATCH 18/18] ledtrig-blkdev: Add initialization & exit functions Ian Pilcher
2021-09-04  6:35 ` [PATCH 00/18] Introduce block device LED trigger Pavel Machek

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=20210903204548.2745354-12-arequipeno@gmail.com \
    --to=arequipeno@gmail.com \
    --cc=axboe@kernel.dk \
    --cc=gregkh@linuxfoundation.org \
    --cc=kabel@kernel.org \
    --cc=linux-block@vger.kernel.org \
    --cc=linux-leds@vger.kernel.org \
    --cc=linux@vger.kernel.org \
    --cc=pavel@ucw.cz \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.