Disable a USB port and the connected hard drive
Table of Contents
And enable it when required.
Also see this related article.
Premise & problem ∆
I have a USB hard drive used only for weekly automated backups. It is always connected to the same port and never gets removed.
At all other times I want this drive to be unmounted, off, invisible, powered down.
I want to save its limited lifetime by keeping it powered down, and I don't want any process to power it up again.
Unfortunately various systemd services are prone to do just that, e.g. systemd-hostnamed, dbus, udisks2, but also command line
utilities like fdisk, smartctl and even hdparm itself.
Waking the drive takes 30s which leads to unholy delays in certain actions (opening files with GtkFileChooser).
Additionally this cheap WD passport drive has very limited powersaving capabilities.
Only the script running the backup should be allowed to power it up again, mount its partition, do the backup, then unmount and power down.
I had hoped a udev rule would be sufficient, but the described issues were still cropping up.
Solution ∆
Off ∆
We will send the hard drive to sleep with hdparm
and then completely switch off that particular USB socket:
# /usr/bin/hdparm -Y "$device"
I don't recommend using kernel assigned drive letters like /dev/sdX
because they can change.
Instead I found the device in /dev/disk/by-id/
.
That was easy.
Now, find the USB port. There's probably different ways, but I went with /sys/bus/usb/devices/X-X
.
Those two numbers (e.g. 2-6 or 1-4 etc.) are also reflected in the output of lsusb -t
(a command I used dozens of times during testing).
# echo "0" > /sys/bus/usb/devices/X-X/power/autosuspend_delay_ms
# echo "auto" > /sys/bus/usb/devices/X-X/power/control
And lastly, unbind the USB port in question:
# echo X-X > /sys/bus/usb/drivers/usb/unbind
This does indeed not power the USB port off, but it's almost completely invisible to the system now and the drive can slumber in peace.
I had a lot of help from this SO article.
On ∆
Just perform the steps in reverse order:
# echo X-X > /sys/bus/usb/drivers/usb/bind
# echo "2000" > /sys/bus/usb/devices/X-X/power/autosuspend_delay_ms
# echo "on" > /sys/bus/usb/devices/X-X/power/control
"2000" and "on" are default values as per kernel documentation.
Files ∆
The script and an example systemd service file can be found in my stuff repository.
Copy hd-usb.service
to /etc/systemd/system/
and edit to your requirements.
Enable the service so it becomes active after a reboot:
# systemctl enable hd-usb
Or start it now:
# systemctl start hd-usb