mirror of
https://github.com/miskcoo/ugreen_dx4600_leds_controller.git
synced 2025-07-22 12:00:37 +02:00
Improve the disk standby check (#40)
Some checks failed
Build kernel module for TrueNAS / build-and-run (push) Has been cancelled
Some checks failed
Build kernel module for TrueNAS / build-and-run (push) Has been cancelled
This commit is contained in:
@@ -220,6 +220,15 @@ Please see `scripts/ugreen-leds.conf` for an example.
|
||||
cp ugreen-blink-disk /usr/bin
|
||||
```
|
||||
|
||||
- (_Optional_) Similarly, to reduce the latency of the standby check, you can enter the `scripts` directory and do the following things:
|
||||
```bash
|
||||
# compile the disk standby checker
|
||||
g++ -std=c++17 -O2 check-standby.cpp -o ugreen-check-standby
|
||||
|
||||
# copy the binary file (the path can be changed, see STANDBY_MON_PATH in ugreen-leds.conf)
|
||||
cp ugreen-check-standby /usr/bin
|
||||
```
|
||||
|
||||
## Disk Mapping
|
||||
|
||||
To make the disk LEDs useful, we should map the disk LEDs to correct disk slots. First of all, we should highlight that using `/dev/sdX` is never a smart idea, as it may change at every boot.
|
||||
|
@@ -8,7 +8,7 @@
|
||||
|
||||
Name: kmod-%{kmod_name}
|
||||
Version: 0.1
|
||||
Release: 16%{?dist}
|
||||
Release: 17%{?dist}
|
||||
Summary: %{kmod_name} kernel module(s)
|
||||
Group: System Environment/Kernel
|
||||
License: GPLv2
|
||||
@@ -83,6 +83,7 @@ popd
|
||||
|
||||
pushd scripts
|
||||
%{__cxx} -std=c++17 -O2 blink-disk.cpp -o ugreen-blink-disk
|
||||
%{__cxx} -std=c++17 -O2 check-standby.cpp -o ugreen-check-standby
|
||||
popd
|
||||
|
||||
whitelist="/lib/modules/kabi-current/kabi_stablelist_%{_target_cpu}"
|
||||
@@ -112,6 +113,7 @@ mkdir -p %{buildroot}%{_bindir}/
|
||||
%{__install} -m 0755 scripts/ugreen-netdevmon %{buildroot}%{_bindir}/
|
||||
%{__install} -m 0755 scripts/ugreen-probe-leds %{buildroot}%{_bindir}/
|
||||
%{__install} -m 0755 scripts/ugreen-blink-disk %{buildroot}%{_bindir}/
|
||||
%{__install} -m 0755 scripts/ugreen-check-standby %{buildroot}%{_bindir}/
|
||||
|
||||
mkdir -p %{buildroot}%{_unitdir}/
|
||||
%{__install} -m 0644 scripts/ugreen-netdevmon@.service %{buildroot}%{_unitdir}/
|
||||
@@ -221,6 +223,7 @@ exit 0
|
||||
%attr(0755, root, root) %{_bindir}/ugreen-netdevmon
|
||||
%attr(0755, root, root) %{_bindir}/ugreen-probe-leds
|
||||
%attr(0755, root, root) %{_bindir}/ugreen-blink-disk
|
||||
%attr(0755, root, root) %{_bindir}/ugreen-check-standby
|
||||
%{_unitdir}/ugreen-netdevmon@.service
|
||||
%{_unitdir}/ugreen-diskiomon.service
|
||||
|
||||
|
17
build-scripts/debian/Dockerfile
Normal file
17
build-scripts/debian/Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM debian:bookworm
|
||||
|
||||
RUN set -ex \
|
||||
&& sed -i -- 's/Types: deb/Types: deb deb-src/g' /etc/apt/sources.list.d/debian.sources \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
cdbs \
|
||||
devscripts \
|
||||
equivs \
|
||||
fakeroot \
|
||||
wget \
|
||||
git \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /tmp/* /var/tmp/*
|
||||
|
||||
|
@@ -1,2 +1,8 @@
|
||||
|
||||
To build a deb, run `sudo bash build.sh`.
|
||||
Build it in docker:
|
||||
|
||||
```
|
||||
bash docker-run.sh
|
||||
```
|
||||
|
||||
The outputs can be found in `./build` directory.
|
||||
|
@@ -15,7 +15,7 @@ Version: $pkgver
|
||||
Architecture: amd64
|
||||
Maintainer: Yuhao Zhou <miskcoo@gmail.com>
|
||||
Depends: dkms
|
||||
Homepage: https://github.com/miskcoo/ugreen_dx4600_leds_controller
|
||||
Homepage: https://github.com/miskcoo/ugreen_leds_controller
|
||||
Description: UGREEN NAS LED driver
|
||||
A reverse-engineered LED driver of UGREEN NAS.
|
||||
EOF
|
||||
|
@@ -15,7 +15,7 @@ Version: $pkgver
|
||||
Architecture: amd64
|
||||
Maintainer: Yuhao Zhou <miskcoo@gmail.com>
|
||||
Depends: dmidecode, smartmontools
|
||||
Homepage: https://github.com/miskcoo/ugreen_dx4600_leds_controller
|
||||
Homepage: https://github.com/miskcoo/ugreen_leds_controller
|
||||
Description: UGREEN NAS LED tools
|
||||
A reverse-engineered LED tools of UGREEN NAS.
|
||||
EOF
|
||||
@@ -35,11 +35,18 @@ done
|
||||
mkdir -p $pkgname/etc/systemd/system
|
||||
cp scripts/*.service $pkgname/etc/systemd/system/
|
||||
# cp scripts/ugreen-ledmon@.service $pkgname/etc/systemd/system/
|
||||
#
|
||||
|
||||
# example config file
|
||||
cp scripts/ugreen-leds.conf $pkgname/etc/ugreen-leds.example.conf
|
||||
|
||||
# compile the disk activities monitor
|
||||
g++ -std=c++17 -O2 scripts/blink-disk.cpp -o ugreen-blink-disk
|
||||
cp ugreen-blink-disk $pkgname/usr/bin
|
||||
|
||||
# compile the disk standby monitor
|
||||
g++ -std=c++17 -O2 scripts/check-standby.cpp -o ugreen-check-standby
|
||||
cp ugreen-check-standby $pkgname/usr/bin
|
||||
|
||||
# change to root
|
||||
chown -R root:root $pkgname/
|
||||
|
||||
|
@@ -1,14 +1,16 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
git clone https://github.com/miskcoo/ugreen_dx4600_leds_controller.git
|
||||
set -x
|
||||
|
||||
cp build-dkms-deb.sh ugreen_dx4600_leds_controller
|
||||
cp build-utils-deb.sh ugreen_dx4600_leds_controller
|
||||
git clone https://github.com/miskcoo/ugreen_leds_controller.git
|
||||
cd ugreen_leds_controller
|
||||
|
||||
cd ugreen_dx4600_leds_controller
|
||||
bash build-dkms-deb.sh
|
||||
bash build-utils-deb.sh
|
||||
if [ ! -z $1 ]; then
|
||||
git checkout $1
|
||||
fi
|
||||
|
||||
bash build-scripts/debian/build-dkms-deb.sh
|
||||
bash build-scripts/debian/build-utils-deb.sh
|
||||
dpkg-name led-ugreen-dkms.deb
|
||||
dpkg-name led-ugreen-utils.deb
|
||||
mv *.deb ../
|
||||
mv *.deb ..
|
||||
|
15
build-scripts/debian/docker-run.sh
Normal file
15
build-scripts/debian/docker-run.sh
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
|
||||
set -x
|
||||
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build
|
||||
fi
|
||||
|
||||
docker build --tag bookworm-build .
|
||||
docker run \
|
||||
--rm \
|
||||
--mount type=bind,source=$(pwd)/build,target=/build \
|
||||
--mount type=bind,source=$(pwd)/build.sh,target=/build.sh \
|
||||
bookworm-build \
|
||||
bash -c "cd /build && bash /build.sh $1"
|
112
scripts/check-standby.cpp
Normal file
112
scripts/check-standby.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <optional>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
std::optional<bool> is_standby_mode(const std::string &device) {
|
||||
|
||||
int fd = open(device.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
if (fd == -1) {
|
||||
std::cerr << "Failed to open device: " << device << std::endl;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
unsigned char args[4] = { WIN_CHECKPOWERMODE1, 0, 0, 0 };
|
||||
|
||||
if (ioctl(fd, HDIO_DRIVE_CMD, args) == -1) {
|
||||
std::cerr << "ioctl failed in checking power mode of " << device << std::endl;
|
||||
close(fd);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return args[2] == 0x00;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
constexpr int preleading_args = 4;
|
||||
|
||||
if (argc < preleading_args + 2 || (argc - preleading_args) % 2 != 0) {
|
||||
std::cerr << "Usage: " << argv[0]
|
||||
<< " <check interval (in second)>"
|
||||
<< " <disk standby color>"
|
||||
<< " <disk normal color>"
|
||||
<< " <block device 1> <led device 1> <block device 2> <led device 2>...\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
int num_devices = (argc - preleading_args) / 2;
|
||||
int checker_sleep_ms = int(std::stod(argv[1]) * 1000);
|
||||
|
||||
std::string standby_color = argv[2];
|
||||
std::string normal_color = argv[3];
|
||||
std::vector<std::string> block_device_paths;
|
||||
std::vector<std::string> led_device_color_paths;
|
||||
|
||||
std::cout << normal_color;
|
||||
|
||||
for (int i = 0; i < num_devices; i++) {
|
||||
std::string block_device = argv[preleading_args + 2 * i];
|
||||
std::string led_device = argv[preleading_args + 2 * i + 1];
|
||||
|
||||
|
||||
block_device_paths.push_back(
|
||||
"/dev/" + block_device);
|
||||
led_device_color_paths.push_back(
|
||||
"/sys/class/leds/" + led_device + "/color");
|
||||
}
|
||||
|
||||
std::vector<bool> device_valid(num_devices, true);
|
||||
std::vector<bool> device_standby(num_devices, false);
|
||||
|
||||
while (true) {
|
||||
for (int i = 0; i < num_devices; i++) {
|
||||
|
||||
if (!device_valid[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto is_standby = is_standby_mode(block_device_paths[i]);
|
||||
|
||||
if (!is_standby.has_value()) {
|
||||
device_valid[i] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_standby.value() != device_standby[i]) {
|
||||
std::fstream led_color(led_device_color_paths[i], std::ios::in | std::ios::out);
|
||||
if (!led_color) {
|
||||
std::cerr << "Failed to open led color file: "
|
||||
<< led_device_color_paths[i] << std::endl;
|
||||
device_valid[i] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string current_color;
|
||||
std::getline(led_color, current_color);
|
||||
|
||||
if (device_standby[i] && current_color == standby_color) {
|
||||
led_color << normal_color << std::endl;
|
||||
} else if (!device_standby[i] && current_color == normal_color) {
|
||||
led_color << standby_color << std::endl;
|
||||
}
|
||||
|
||||
device_standby[i] = is_standby.value();
|
||||
}
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(checker_sleep_ms));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@@ -8,6 +8,7 @@ exit-ugreen-diskiomon() {
|
||||
kill $smart_check_pid 2>/dev/null
|
||||
kill $zpool_check_pid 2>/dev/null
|
||||
kill $disk_online_check_pid 2>/dev/null
|
||||
kill $standby_checker_pid 2>/dev/null
|
||||
}
|
||||
|
||||
# trap exit and remove lockfile
|
||||
@@ -111,6 +112,14 @@ BRIGHTNESS_DISK_LEDS=${BRIGHTNESS_DISK_LEDS:="255"}
|
||||
|
||||
{ lsmod | grep ledtrig_oneshot > /dev/null; } || { modprobe -v ledtrig_oneshot && sleep 2; }
|
||||
|
||||
function is_disk_healthy_or_standby() {
|
||||
if [[ "$1" == "$COLOR_DISK_HEALTH" || "$1" == "$COLOR_DISK_STANDBY" ]]; then
|
||||
return 0 # 0 means successful
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function disk_enumerating_string() {
|
||||
if [[ $MAPPING_METHOD == ata ]]; then
|
||||
ls -ahl /sys/block | sed 's/\/$//' | awk '{
|
||||
@@ -221,8 +230,9 @@ if [ "$CHECK_ZPOOL" = true ]; then
|
||||
|
||||
if [[ -v "zpool_ledmap[${zpool_dev_name}]" ]]; then
|
||||
led=${zpool_ledmap[$zpool_dev_name]}
|
||||
led_color=$(cat /sys/class/leds/$led/color)
|
||||
|
||||
if [[ "$(cat /sys/class/leds/$led/color)" != "$COLOR_DISK_HEALTH" ]]; then
|
||||
if ! is_disk_healthy_or_standby "$led_color"; then
|
||||
continue;
|
||||
fi
|
||||
|
||||
@@ -256,7 +266,9 @@ if [ "$CHECK_SMART" = true ]; then
|
||||
(
|
||||
while true; do
|
||||
for led in "${!devices[@]}"; do
|
||||
if [[ "$(cat /sys/class/leds/$led/color)" != "$COLOR_DISK_HEALTH" ]]; then
|
||||
|
||||
led_color=$(cat /sys/class/leds/$led/color)
|
||||
if ! is_disk_healthy_or_standby "$led_color"; then
|
||||
continue;
|
||||
fi
|
||||
|
||||
@@ -265,9 +277,7 @@ if [ "$CHECK_SMART" = true ]; then
|
||||
/usr/sbin/smartctl -H /dev/${dev} -n standby,1 &> /dev/null
|
||||
RET=$?
|
||||
|
||||
if [[ $RET -eq 1 ]]; then
|
||||
echo "$COLOR_DISK_STANDBY" > /sys/class/leds/$led/color
|
||||
elif [[ $RET -gt 1 ]]; then
|
||||
if [[ $RET -gt 1 ]]; then
|
||||
echo "$COLOR_SMART_FAIL" > /sys/class/leds/$led/color
|
||||
echo Disk failure detected on /dev/$dev at $(date +%Y-%m-%d' '%H:%M:%S)
|
||||
continue
|
||||
@@ -286,21 +296,7 @@ fi
|
||||
dev=${devices[$led]}
|
||||
|
||||
led_color=$(cat /sys/class/leds/$led/color)
|
||||
|
||||
if [[ "$led_color" == "$COLOR_DISK_STANDBY" ]]; then
|
||||
# Check if disk is still in standby
|
||||
/usr/sbin/smartctl -H /dev/${dev} -n standby,1 &> /dev/null
|
||||
RET=$?
|
||||
|
||||
if [[ $RET -eq 0 ]]; then
|
||||
led_color="$COLOR_DISK_HEALTH"
|
||||
echo $led_color > /sys/class/leds/$led/color
|
||||
elif [[ $RET -gt 1 ]]; then
|
||||
echo "$COLOR_SMART_FAIL" > /sys/class/leds/$led/color
|
||||
echo Disk failure detected on /dev/$dev at $(date +%Y-%m-%d' '%H:%M:%S)
|
||||
continue
|
||||
fi
|
||||
elif [[ "$led_color" != "$COLOR_DISK_HEALTH" ]]; then
|
||||
if ! is_disk_healthy_or_standby "$led_color"; then
|
||||
continue;
|
||||
fi
|
||||
|
||||
@@ -315,18 +311,26 @@ fi
|
||||
) &
|
||||
disk_online_check_pid=$!
|
||||
|
||||
|
||||
diskiomon_parameters() {
|
||||
for led in "${!devices[@]}"; do
|
||||
echo ${devices[$led]} $led
|
||||
done
|
||||
}
|
||||
|
||||
# monitor disk standby modes
|
||||
STANDBY_MON_PATH=${STANDBY_MON_PATH:=/usr/bin/ugreen-check-standby}
|
||||
STANDBY_CHECK_INTERVAL=${STANDBY_CHECK_INTERVAL:=1}
|
||||
if [ -f "${STANDBY_MON_PATH}" ]; then
|
||||
${STANDBY_MON_PATH} ${STANDBY_CHECK_INTERVAL} "${COLOR_DISK_STANDBY}" "${COLOR_DISK_HEALTH}" $(diskiomon_parameters) &
|
||||
standby_checker_pid=$1
|
||||
fi
|
||||
|
||||
# monitor disk activities
|
||||
BLINK_MON_PATH=${BLINK_MON_PATH:=/usr/bin/ugreen-blink-disk}
|
||||
if [ -f "${BLINK_MON_PATH}" ]; then
|
||||
|
||||
diskiomon_parameters() {
|
||||
echo ${LED_REFRESH_INTERVAL}
|
||||
for led in "${!devices[@]}"; do
|
||||
echo ${devices[$led]} $led
|
||||
done
|
||||
}
|
||||
|
||||
${BLINK_MON_PATH} $(diskiomon_parameters)
|
||||
${BLINK_MON_PATH} ${LED_REFRESH_INTERVAL} $(diskiomon_parameters)
|
||||
|
||||
else
|
||||
declare -A diskio_data_rw
|
||||
|
@@ -23,6 +23,12 @@ MAPPING_METHOD=ata
|
||||
# The path of the compiled diskio monitor (OPTIONAL)
|
||||
BLINK_MON_PATH=/usr/bin/ugreen-blink-disk
|
||||
|
||||
# The path of the compiled standby monitor (OPTIONAL)
|
||||
STANDBY_MON_PATH=/usr/bin/ugreen-check-standby
|
||||
|
||||
# The sleep time between disk standby checks (default: 1 seconds)
|
||||
STANDBY_CHECK_INTERVAL=1
|
||||
|
||||
# The serial numbers of disks (used only when MAPPING_METHOD=serial)
|
||||
# You need to record them before inserting to your NAS, and the corresponding disk slots.
|
||||
# If you have 4 disks, with serial numbers: SN1 SN2 SN3 SN4,
|
||||
|
Reference in New Issue
Block a user