updated Pi NAS: automatic hard drive spin-down, and introducing virtual USB unplugging
After running for only a year my last Raspberry Pi Zero NAS died. The hard drive failed. It's not clear if it was the disk's fault, or if the 1A USB hub that powered the drive was insufficient and caused the heads to crash. Either way, the 500GB WD My Passport USB3 drive stopped being able to spin up, making a loud whir-click every 2 seconds or so. Time to build a new setup. The Pi itself seemed fine, thankfully.
I switched to a 2TB WD My Book with its own OEM 12v power supply, so I knew that the supplied power was sufficient. It's somewhat power hungry when spinning but idle: around 6.3w. If you can get it to go into standby mode that drops to 1.7w. Unplugging the USB drops it all the way to .7w. So we HAVE to get the drive to go into standby mode and it would be nice to get the drive unplugged somehow. Out of the box it appears to be stuck always spinning under linux, so there's no option but to dig in.
Unfortunately I was back to square one on making the drive spin down. So far no drive I've worked with (a "coolmax 500gb" and the "WD my passport 500gb") supported the same method for automatically going into standby under linux.
hdparm -S 1 /dev/sda did nothing mounted or not.
hdparm -B 1 /dev/sda "HDIO_DRIVE_CMD failed: Input/output error APM_level = not supported".
sdparm --flexible --command=stop /dev/sda just did nothing.
smartctl -d sat --set=standby,now /dev/sda did nothing while the drive was mounted. After unmounting it did.
There are ways to unmount drives that are not in use. While researching them I realized there might be a way to also unplug the usb, virtually, too... So I decided to roll my own solution.
First, we need automount (autofs) which knows how to mount hard drives on demand and unmount after a timeout.
apt-get install autofs
Here's my usbOffOnIdle script, which I put in /usr/local/bin:
Finally, we can use my script to unplug the drive on bootup. Using crontab -e add this line:
@reboot sleep 600; /usr/local/bin/usbOffOnIdle
There's more than that to setting up a NAS, of course. All that was just to keep the power demands low, and to (probably) reduce wear on the drive. My previous post explains how to set up the rest of the Pi Zero NAS using Unison. You can ignore the parts about hard drive idling and fstab.
Some sources:
https://unix.stackexchange.com/questions/101680/automount-post-unmount-script
https://www.raspberrypi.org/forums/viewtopic.php?t=134351
I switched to a 2TB WD My Book with its own OEM 12v power supply, so I knew that the supplied power was sufficient. It's somewhat power hungry when spinning but idle: around 6.3w. If you can get it to go into standby mode that drops to 1.7w. Unplugging the USB drops it all the way to .7w. So we HAVE to get the drive to go into standby mode and it would be nice to get the drive unplugged somehow. Out of the box it appears to be stuck always spinning under linux, so there's no option but to dig in.
Unfortunately I was back to square one on making the drive spin down. So far no drive I've worked with (a "coolmax 500gb" and the "WD my passport 500gb") supported the same method for automatically going into standby under linux.
My failures:
hdparm -S 1 /dev/sda did nothing mounted or not.
hdparm -B 1 /dev/sda "HDIO_DRIVE_CMD failed: Input/output error APM_level = not supported".
sdparm --flexible --command=stop /dev/sda just did nothing.
smartctl -d sat --set=standby,now /dev/sda did nothing while the drive was mounted. After unmounting it did.
There are ways to unmount drives that are not in use. While researching them I realized there might be a way to also unplug the usb, virtually, too... So I decided to roll my own solution.
My success: spin down and unplug USB too!
First, we need automount (autofs) which knows how to mount hard drives on demand and unmount after a timeout.
apt-get install autofs
we also need at for some of the scheduling.
apt-get install at
The key thing about autofs is that it executes a shell script before mounting, so we can do whatever magic we want as part of that.
Here's the script, named /etc/auto.disks
#!/bin/bash
# $1 is passed-over from automount
# key refers to the mount point we are looking for
key="$1"
if [ "$key" == "sda" ]; then
echo 1 > /sys/devices/platform/soc/20980000.usb/buspower
while ! [ -b /dev/$key ]; # wait until the file can be found
do
sleep .5
done
echo usbOffOnIdle | at now+11min
fi
# default mount options
opts="-fstype=ext4,rw"
# if a block device exists at /dev/[key]
# pass it back to automount
[ -b /dev/${key} ] && { echo "$opts :/dev/${key}"; }
SDA is my hard drive. We manage it as a special case, turning on the USB port when we want to mount it, and waiting until the device is detected before continuing. We also fire off an at command which will be responsible for shutting off the device when not being used, see below. It will first start checking for idle at 11 minutes after mounting.
echo 1 > sys/devices/platform/soc/20980000.usb/ buspower
is raspberry pi zero specific, and turns power on to the USB port (we'll turn it off later, and at boot).
We need to make autofs use this script by editing auto.master and adding
/mnt /etc/auto.disks --timeout=600
/mnt /etc/auto.disks --timeout=600
which makes it call our script when trying to mount any device under /mnt, as in ls /mnt/sda . The timeout is in seconds.
So now we have a system that will turn on USB power whenever the drive is mounted, and will unmount 10 minutes after it is last used. But there's no unmount script triggered by autofs, which is why I need at, a handy scheduler that we can run in a loop until it detects the device is unmounted.
#!/bin/bash
if `ls /mnt | grep -q sda`; then
echo usbOffOnIdle | at now+10min
else
else
echo unmounted `date` >> /root/log
smartctl -d sat --set=standby,now /dev/sda
sleep 10
echo 0 > /sys/devices/platform/soc/20980000.usb/buspower
fi
I use if `ls /mnt | grep -q sda`; to check for the mount because the regular bash -e option will actually force the device to mount- oops!
If the drive is still mounted I just call myself again 10 minutes in the future and wait for autofs to do the umount-ing. If it's not mounted, I put the drive in standby (probably not needed) sleep a bit to be sure it happened, and then turn off power to the USB.
In order to make the drive spin down first, you do need smartctl:
If the drive is still mounted I just call myself again 10 minutes in the future and wait for autofs to do the umount-ing. If it's not mounted, I put the drive in standby (probably not needed) sleep a bit to be sure it happened, and then turn off power to the USB.
In order to make the drive spin down first, you do need smartctl:
apt-get install smartctl
Finally, we can use my script to unplug the drive on bootup. Using crontab -e add this line:
@reboot sleep 600; /usr/local/bin/usbOffOnIdle
Wait, that's it?
Some sources:
https://unix.stackexchange.com/questions/101680/automount-post-unmount-script
https://www.raspberrypi.org/forums/viewtopic.php?t=134351
Postscript
It's been running one year with 99.9% uptime. The only downtime seems to be network related but I'm not sure. I have it reboot once a week and that's reliably brought it back up.