Linux kernel module to blink LEDs on block device activity
Update: Starting with version 4.8, Linux now has built-in support for
blinking LEDs (through the disk-activity
trigger). However Linux's built-in
disk-activity
trigger is not configurable, whereas this module enables the
user to specify what disks to monitor and a few other parameters.
My ThinkPad laptop has no hard disk activity LED, but just a single power LED that can be controlled in software (through Linux's LED infrastructure). The power LED's default always-on function is basically useless, and I have decided to turn it into an hard disk activity LED.
This repository contains a Linux kernel module that implements a
block-activity
LED trigger that can be assigned to LEDs as follows:
# echo block-activity > /sys/class/leds/tpacpi\:\:power/trigger
This module has been tested on Fedora 36 x86_64, kernel version 5.17.13.
Compile the kernel module (with a simple in-source make
) as root, then
load it with:
# insmod block_led_trigger.ko devices=8:0,8:16
Note: This module has to be compiled as root because regular users cannot read the actual contents of /proc/kallsyms. See the Warnings section for an explanation on why this file is needed at compile time.
(see the next paragraph for the available command-line arguments)
Choose the LED you want to control (you can browse available
LEDs in the /sys/class/leds/
directory) and check that it can actually be
controlled by echo
'ing a few 0
or 1
values to its brightness
file.
Finally, assign the block-activity
LED trigger with:
# echo block-activity > /sys/class/leds/$YOUR_LED_HERE/trigger
blink_delay_ms
(default: 30) is the blink interval in milliseconds.
devices
(default: 8:0) is a comma-separated list of devices to monitor. The
LED will blink whenever one of those devices is servicing an I/O operation.
Devices must be listed in MAJOR:MINOR
format (e.g. 8:0 for sda, 8:16 for
sdb, 8:32 for sdc, 8:48 for sdd, and so on - if unsure, run
ls -la /dev/sd?
to discover the values on your running system).
invert_brightness
(default: N) lets you invert the LED output state. If N
is selected, the LED will stay switched off if there is no I/O activity; if Y
is selected, the LED will stay switched on.
This module uses the block_rq_issue
tracepoint defined by the Linux kernel,
which is exposed to userland programs through the blktrace API.
Unfortunately, it is not exposed to kernel modules (in particular, the
__tracepoint_block_rq_issue
variable is not exported and therefore it cannot
be resolved by the module loader at runtime). For this reason, the Makefile
contains a grep
command to extract its address from the running kernel's memory
map (/proc/kallsyms) and resolve its address at compile time.
The generated kernel module is therefore very dependent on the memory layout of the kernel it was compiled against. If you try to load the compiled module on a different kernel binary (even if it's the very same kernel version), the address of that variable will likely be different and the module will refuse to load.
If the kernel was compiled with CONFIG_RELOCATABLE
, it is even possible for the
address to change across reboots with the same kernel binary.
Please note that all addresses in /proc/kallsyms might appear as zero to non-root users. Therefore, this module must be compiled as root.
The repository also contains a make-rpm.sh
script that generates an RPM
package containing a systemd service that:
- compiles the module against the running kernel
- loads it and assigns the power LED (you may want to tweak the
block-led-trigger
script)
The RPM package can be installed and started as follows:
# ./make-rpm.sh
# dnf install block-led-trigger-0.5-1.fc36.noarch.rpm
# systemctl start block-led-trigger
To run the service automatically on boot:
# systemctl enable block-led-trigger
Note that the service script will rebuild the module on each boot. This
operation usually takes negligible time on a modern CPU, but it can be probably
be avoided by creating proper akmods
/dkms
packages, provided
CONFIG_RELOCATABLE
does not interfere (see Warnings above).