341 lines
15 KiB
Markdown
341 lines
15 KiB
Markdown
# hd-idle
|
|
|
|
Reimplementation of _Christian Mueller's_ [hd-idle](http://hd-idle.sf.net) with some extra features.
|
|
|
|
`hd-idle` is a utility program for spinning-down external disks after a period of idle time.
|
|
Since most external IDE disk enclosures don't support setting the IDE idle timer,
|
|
a program like `hd-idle` is required to spin down idle disks automatically.
|
|
|
|
**Index**
|
|
* [Extra features](#extra-features)
|
|
* [Support ATA commands](#support-ata-commands)
|
|
* [Monitor the skew between monitoring cycles](#monitor-the-skew-between-monitoring-cycles)
|
|
* [Resolve symlinks in runtime](#resolve-symlinks-in-runtime)
|
|
* [Log disk spin up](#log-disk-spin-up)
|
|
* [Use disk partitions or device mapper to calculate activity](#use-disk-partitions-or-device-mapper-to-calculate-activity)
|
|
* [Install](#Install)
|
|
* [Precompiled binaries](#precompiled-binaries)
|
|
* [Build from source](#build-from-source)
|
|
* [Run hd-idle](#run-hd-idle)
|
|
* [Configuration](#Configuration)
|
|
* [Understand the logs](#understand-the-logs)
|
|
* [Standard log](#standard-log)
|
|
* [Log file](#log-file)
|
|
* [Warning on spinning down disks](#warning-on-spinning-down-disks)
|
|
* [Troubleshot](#Troubleshot)
|
|
* [LUKS support](#luks-support)
|
|
* [SCSI response not ok](#scsi-response-not-ok)
|
|
|
|
## Extra features
|
|
|
|
List of extra features compared to the original `hd-idle`:
|
|
|
|
### Support ATA commands
|
|
|
|
The implementation of `hd-idle` written by _Christian Mueller_ relies on the `SCSI` api to work.
|
|
When listing the drives by id, disks starting with `usb` stop using the original implementation,
|
|
but disk starting with `ata` do not.
|
|
|
|
$ ls /dev/disk/by-id/
|
|
|
|
ata-WDC_WD40EZRX-
|
|
ata-WDC_WD50EZRX-
|
|
usb-WD_My_Book_1140_
|
|
|
|
[hdparm](https://en.wikipedia.org/wiki/Hdparm) on the other hand always stops the drives without any problems.
|
|
It uses `ATA` api calls to send disks to standby. `hd-idle` comes with `ATA` commands support to replicate `hdparm`'s api calls.
|
|
|
|
### Monitor the skew between monitoring cycles
|
|
|
|
Identify if the sleep took longer than expected and reset the spun down flag if it waited too long for the main loop sleep.
|
|
This should capture suspend events as well as excessive machine load.
|
|
|
|
### Resolve symlinks in runtime
|
|
|
|
`hd-idle` can resolve disk symlinks also in runtime. Disks added after application's start won't be hidden.
|
|
|
|
### Log disk spin up
|
|
|
|
Show in standard output when disks spin up.
|
|
|
|
### Use disk partitions or device mapper to calculate activity
|
|
|
|
The disk activity is calculated by watching read/write changes on partition or device mapper level instead of disk level.
|
|
This is required for kernels newer than 5.4 LTS, because disk monitoring tools change read/write values on disk level,
|
|
although there's no real activity on the disk itself.
|
|
When using LUKS, activity will happen on the device mapper device mapped to the corresponding disk.
|
|
|
|
## Install
|
|
|
|
There are various ways of installing `hd-idle`:
|
|
|
|
### Precompiled binaries
|
|
|
|
Precompiled binaries for released versions are available in the
|
|
[*releases*](https://github.com/adelolmo/hd-idle/releases) section.
|
|
|
|
### Build from source
|
|
|
|
To build `hd-idle` from the source code yourself you need to have a working
|
|
Go environment with [version 1.16 or greater installed](http://golang.org/doc/install).
|
|
|
|
Open a terminal and execute these commands:
|
|
|
|
git clone https://github.com/adelolmo/hd-idle
|
|
cd hd-idle
|
|
make
|
|
|
|
On Debian you can also build the package yourself using `dpkg-buildpackage`:
|
|
|
|
git clone https://github.com/adelolmo/hd-idle.git
|
|
cd hd-idle
|
|
dpkg-buildpackage -a armhf -us -uc -b
|
|
|
|
In the example above, the package is built for `armhf`, but you can build it also for the platforms `i386`, `amd64`, and `arm64`
|
|
by substituting the parameter `-a`.
|
|
|
|
Then install the package:
|
|
|
|
# dpkg -i ../hd-idle*.deb
|
|
|
|
## Run hd-idle
|
|
|
|
In order to run `hd-idle`, type:
|
|
|
|
$ hd-idle
|
|
|
|
This will start `hd-idle` with the default options, causing all `SCSI`
|
|
(read: USB, Firewire, SCSI, ...) hard disks to spin down after 10 minutes of inactivity.
|
|
|
|
If the Debian package was installed, after editing `/etc/default/hd-idle` and enabling it (`START_HD_IDLE=true`),
|
|
run hd-idle with:
|
|
|
|
# systemctl start hd-idle
|
|
|
|
To enable `hd-idle` on reboot:
|
|
|
|
# systemctl enable hd-idle
|
|
|
|
Please note that `hd-idle` uses */proc/diskstats* to read disk statistics. If
|
|
this file is not present, `hd-idle` won't work.
|
|
|
|
In case of problems, use the debug option *-d* to get further information.
|
|
|
|
## Configuration
|
|
|
|
Command line options:
|
|
|
|
+ -a *name*
|
|
Set device name of disks for subsequent idle-time
|
|
parameters *-i*. This parameter is optional in the
|
|
sense that there's a default entry for all disks
|
|
which are not named otherwise by using this
|
|
parameter. This can also be a symlink
|
|
(e.g. /dev/disk/by-uuid/...)
|
|
|
|
+ -i *idle_time*
|
|
Idle time in seconds for the currently named disk(s)
|
|
(-a *name*) or for all disks.
|
|
Setting this value to `0` will never spin down the disk(s).
|
|
|
|
+ -c *command_type*
|
|
Api call to stop the device. Possible values are `scsi`
|
|
(default value) and `ata`.
|
|
|
|
+ -p *power_condition*
|
|
Power condition to send with the issued SCSI START STOP UNIT command. Possible values
|
|
are `0-15` (inclusive). The default value of `0` works fine for disks accessible via the
|
|
SCSI layer (USB, IEEE1394, ...), but it will *NOT* work as intended with real SCSI / SAS disks.
|
|
A stopped SAS disk will not start up automatically on access, but requires a startup command for reactivation.
|
|
Useful values for SAS disks are `2` for idle and `3` for standby.
|
|
|
|
+ -s *symlink_policy*
|
|
Set the policy to resolve symlinks for devices. If set
|
|
to `0`, symlinks are resolved only on start. If set to `1`,
|
|
symlinks are also resolved on runtime until success.
|
|
By default symlinks are only resolved on start. If the
|
|
symlink doesn't resolve to a device, the default
|
|
configuration will be applied.
|
|
|
|
+ -l *logfile*
|
|
Name of logfile (written only after a disk has spun
|
|
up or down). Please note that this option might cause the
|
|
disk which holds the logfile to spin up just because
|
|
another disk had some activity. On single-disk systems,
|
|
this option should not cause any additional spinups.
|
|
On systems with more than one disk, the disk where the log
|
|
is written will be spun up. On raspberry based systems the
|
|
log should be written to the SD card.
|
|
|
|
Miscellaneous options:
|
|
|
|
+ -t *disk*
|
|
Spin-down the specified disk immediately and exit.
|
|
|
|
+ -d
|
|
Debug mode. It will print debugging info to
|
|
stdout/stderr (/var/log/syslog if started with systemctl)
|
|
|
|
+ -h
|
|
Print usage information.
|
|
|
|
Regarding the parameter *-a*:
|
|
|
|
The parameter *-a* can be used to set a filter on the disk's device name (omit /dev/)
|
|
for subsequent idle-time settings.
|
|
|
|
1)
|
|
A *-i* option before the first *-a* option will set the default idle time.
|
|
|
|
2)
|
|
In order to disable spin-down of disks per default, and then re-enable
|
|
spin-down on selected disks, set the default idle time to 0.
|
|
|
|
Example:
|
|
```
|
|
hd-idle -i 0 -a sda -i 300 -a sdb -i 1200
|
|
```
|
|
This example sets the default idle time to 0 (meaning hd-idle will never
|
|
try to spin down a disk) and the default api command to `scsi`, then sets explicit
|
|
idle times for disks which have the string `sda` or `sdb` in their device name.
|
|
|
|
3)
|
|
The option *-c* allows to set the api call that sends the spindown command.
|
|
Possible values are `scsi` (the default value) or `ata`.
|
|
|
|
Example:
|
|
```
|
|
hd-idle -i 0 -c ata -a sda -i 300 -a sdb -i 1200 -c scsi
|
|
```
|
|
This example sets the default idle time to 0 (meaning hd-idle will never
|
|
try to spin down a disk) and the default api command to `ata`, then sets explicit
|
|
idle times for disks which have the string `sda` or `sdb` in their device name
|
|
and sets `sdb` to use `scsi` api command.
|
|
|
|
## Understand the logs
|
|
|
|
By default `hd-idle` only logs to the standard output. You can find them in the syslog if the application starts via service.
|
|
|
|
If you set the log file (`-l` flag) then the application writes extra details to it. (Check the [Configuration](#Configuration) section).
|
|
|
|
### Standard log
|
|
|
|
The standard log output registers two kinds of events:
|
|
|
|
* disk spin up
|
|
* disk spin down
|
|
|
|
```
|
|
Aug 8 00:14:55 enterprise hd-idle[9958]: sda spindown
|
|
Aug 8 00:14:55 enterprise hd-idle[9958]: sdb spindown
|
|
Aug 8 00:14:56 enterprise hd-idle[9958]: sdc spindown
|
|
Aug 8 00:17:55 enterprise hd-idle[9958]: sdb spinup
|
|
Aug 8 00:28:55 enterprise hd-idle[9958]: sdb spindown
|
|
```
|
|
|
|
### Log file
|
|
|
|
You can enable the log file with the flag `-l` followed by the log path. (Check the [Configuration](#Configuration) section).
|
|
|
|
This is the kind of entry shown in the log file:
|
|
|
|
```
|
|
date: 2020-07-30, time: 05:28:01, disk: sdc, running: 601, stopped: 76654
|
|
```
|
|
|
|
Explanation:
|
|
* `date` and `time` when the disk spins up.
|
|
* `disk` involved.
|
|
* `running` seconds the device was running before it spun down the last time.
|
|
* `stopped` seconds since last spin down. This is the time the disk was asleep before spinning up.
|
|
|
|
**Important Note:**
|
|
|
|
The log file is written after a full cycle of running-stopped-wakeup.
|
|
|
|
A bit more on `running` explained with the above example:
|
|
|
|
| timestamp |disk spin| event |new disk spin| running | stopped |
|
|
|:-----------------:|:-------:|:-----------:|:-----------:|:------------------------:|:-------------------------------------------------------:|
|
|
|2020-07-29 07:59:57| down |disk activity| up | ? | ? |
|
|
|2020-07-29 08:09:58| up | go to sleep | down | - | - |
|
|
|2020-07-30 05:28:01| down |disk activity| up |08:09:58 - 07:59:57 = 601s|2020-07-30 05:28:01 - 2020-07-29 08:09:58 = ~21h (76654s)|
|
|
|
|
Explanation:
|
|
|
|
At 07:59:57 the disk is on standby and hd-idle detects disk activity.
|
|
|
|
At 08:09:58 the disk is active and hd-idle determines inactivity of the disk and spins it down.
|
|
|
|
At 05:28:01 on the next day the disk is on standby and hd-idle detects disk activity. It writes on the log file 601s of previous disk spin up and ~21h of standby.
|
|
|
|
|
|
## Warning on spinning down disks
|
|
|
|
A word of caution: hard disks don't like spinning up too often. Laptop disks
|
|
are more robust in this respect than desktop disks but if you set your disks
|
|
to spin down after a few seconds you may damage the disk over time due to the
|
|
stress the spin-up causes on the spindle motor and bearings. It seems that
|
|
manufacturers recommend a minimum idle time of 3-5 minutes, the default in
|
|
`hd-idle` is 10 minutes.
|
|
|
|
You have been warned...
|
|
|
|
# Troubleshot
|
|
|
|
This section covers some usual issues that user's face while using `hd-idle`.
|
|
|
|
## LUKS support
|
|
|
|
Using encrypted disk or partitions with LUKS is supported by the use of symlinks.
|
|
|
|
1. Run the following command with you're disk mounted:
|
|
`sudo lsblk /dev/sd* -o PATH,FSSIZE,LABEL,UUID,PARTLABEL,PARTUUID,MODEL,SIZE,SERIAL,TYPE,WWN`
|
|
|
|
```
|
|
PATH FSSIZE LABEL UUID PARTLABEL PARTUUID MODEL SIZE SERIAL TYPE WWN
|
|
/dev/sde ST400 3.7T ZGY0LB disk 0x5000c500a3d1d419
|
|
/dev/sde1 100e952e-0ffb-4b73-bb1a-8401d4fe56c0 dropbox 14a81aa8-c2c9-448e-967b-85d87dc9b488 1T part 0x5000c500a3d1d419
|
|
/dev/sde1 100e952e-0ffb-4b73-bb1a-8401d4fe56c0 dropbox 14a81aa8-c2c9-448e-967b-85d87dc9b488 1T part 0x5000c500a3d1d419
|
|
/dev/sde2 2.6T three 175e2227-d24f-4ad0-9e42-2ddb8846682d d2792423-3c07-44fe-ab6b-a1aca61c73a5 2.7T part 0x5000c500a3d1d419
|
|
/dev/sde2 2.6T three 175e2227-d24f-4ad0-9e42-2ddb8846682d d2792423-3c07-44fe-ab6b-a1aca61c73a5 2.7T part 0x5000c500a3d1d419
|
|
/dev/mapper/luks-100e952e-0ffb-4b73-bb1a-8401d4fe56c0
|
|
1007.8G dropbox
|
|
649dd15e-6750-472c-8185-4d76bffc2490 1024G crypt
|
|
```
|
|
|
|
You have to take symlinks that resolve to disk devices: `/dev/sd*`.
|
|
|
|
In the example above `/dev/mapper/luks-100e952e-0ffb-4b73-bb1a-8401d4fe56c0` is the Path to the encrypted partition,
|
|
which WWN is `0x5000c500a3d1d419`.
|
|
|
|
2. Run the following command to see which devices the system has identified using `by-id`:
|
|
`sudo ls -lv /dev/disk/by-id/`
|
|
|
|
Output:
|
|
```
|
|
lrwxrwxrwx 1 root root 9 Jul 18 15:56 ata-ST4000DM005-2DP166_ZGY0LBRB -> ../../sde
|
|
lrwxrwxrwx 1 root root 10 Jul 18 16:01 ata-ST4000DM005-2DP166_ZGY0LBRB-part1 -> ../../sde1
|
|
lrwxrwxrwx 1 root root 10 Jul 18 15:56 ata-ST4000DM005-2DP166_ZGY0LBRB-part2 -> ../../sde2
|
|
lrwxrwxrwx 1 root root 9 Jul 18 15:56 wwn-0x5000c500a3d1d419 -> ../../sde
|
|
lrwxrwxrwx 1 root root 10 Jul 18 16:01 wwn-0x5000c500a3d1d419-part1 -> ../../sde1
|
|
lrwxrwxrwx 1 root root 10 Jul 18 15:56 wwn-0x5000c500a3d1d419-part2 -> ../../sde2
|
|
```
|
|
|
|
Here we see that we can either use `ata-ST4000DM005-2DP166_ZGY0LBRB` or `wwn-0x5000c500a3d1d419` as symlinks.
|
|
|
|
3. Edit `/etc/default/hd-idle` to use the symlink you prefer.
|
|
In my case, I went with the symlink using WWN (unique storage identifier), yet I could have chosen MODEL (device identifier) instead.
|
|
|
|
`HD_IDLE_OPTS='-i 0 -c ata -s 1 -l /var/log/hd-idle.log -a /dev/disk/by-id/wwn-0x5000c500a3d1d419 -i 600'`
|
|
Or
|
|
`HD_IDLE_OPTS='-i 0 -c ata -s 1 -l /var/log/hd-idle.log -a /dev/disk/by-id/ata-ST4000DM005-2DP166_ZGY0LBRB -i 600'`
|
|
|
|
## SCSI response not ok
|
|
|
|
You can find information about the issue here: [SCSI-response-not-ok](https://github.com/adelolmo/hd-idle/wiki/SCSI-response-not-ok)
|
|
|
|
## License
|
|
|
|
GNU General Public License v3.0, see [LICENSE](https://github.com/adelolmo/hd-idle/blob/master/LICENSE).
|