Prevent a USB external hard drive from sleeping

Just my 2 cents...

It is more than true that spinning down the disks decreases their service life. Years of experience have shown that starting and stopping the disk motor causes far more fatigue than 24/7 spin. All my disks with big start/stop count have reallocated sectors and all my disks that spin 10 years 24/7 are (believe it or not) good as new. After all, disks are made for spinning not for idling, so if your priority is less fatigue than power consumption feel free to have your disks 24/7 spinning.

I have an external 2TB disk that spins down after 30 minutes of inactivity. The disk is meant to be powered on 24/7 for backing up purposes and acting as a small NAS attached to an Orange PI.

I used the following udev rule in

/etc/udev/rules.d

(It never worked as the spin down is in disks firmware)

SUBSYSTEM=="usb", TEST=="power/autosuspend" ATTR{power/autosuspend}="-1"

Although the disk supports the

hdparm -B

I wrote a small daemon process that can run at boot time in

/etc/rc.local

that writes 10 times in cicles the current date and time in a log file so the disk is always on. Feel free to modify as you like.

Command line options are: the target directory to write awake.log and (optionally) the time delay (default 300)

e.g.

/usr/sbin/disk_awake /mnt/some_disk/keep_alive 30

the code: (you can compile with gcc)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <time.h>

int main(int argc, char* argv[])
{
FILE *fp=NULL;
pid_t process_id=0;
pid_t sid=0;
int secs=300;
char log_file[512];
time_t raw_time;
struct tm *time_info;
int ticks=0;
unsigned long step=1;

if (argc<2||argc>3)
{
 printf("Usage: %s target_directory [seconds]\n",argv[0]);
 exit(1);
}
if (strlen(argv[1])>500)
{
 printf("String length of target_directory is HUGE!\n");
 exit(1);
}
if (chdir(argv[1])<0)
{
 printf("Directory %s does not exist\n",argv[1]);
 exit(1);
}
strcpy(log_file,argv[1]);
strcat(log_file,"/awake.log");
if (!(fp=fopen(log_file,"w+")))
{
 printf("Could not open log file %s\n",log_file);
 exit(1);
}
if (!(argv[2]))
{
 printf("Delay argument not specified. Defaulting to 300 seconds\n");
 secs=300;
}
if (argv[2]&&(secs=atoi(argv[2]))<=0)
{
 printf("Could not parse delay option. Defaulting to 300 seconds\n");
 secs=300;
}
printf("Delay interval %d seconds\n",secs);
process_id=fork();
if (process_id<0)
{
printf("Could not fork()\n");
exit(1);
}
if (process_id>0)
{
printf("Started with pid %d\n", process_id);
exit(0);
}
umask(0);
sid=setsid();
if(sid<0)
{
printf("Could not setsid()\n");
exit(1);
}
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
while (1)
{
if (ticks==10)
{
 fclose(fp);
 if (!(fp=fopen(log_file,"w+"))) exit(1);
 ticks=0;step++;
}
time(&raw_time);
time_info=localtime(&raw_time);
fprintf(fp,"%s %lu : %s","Step",step,asctime(time_info));
fflush(fp);
ticks++;
sleep(secs);
}
fclose(fp);
return(0);
}

This solution (for Linux) from http://www.arrfab.net/blog/?p=107 has helped for a 1TB Seagate Portable drive which kept going to sleep:

# sdparm --clear=STANDBY /dev/sdc -S

The drive now is immediately responsive even when left idle for an hour. Didn't test yet whether the setting is saved across restarts etc, though.


I have found that the following cronjob works for me.

*/5 * * * * /bin/touch /dev/sdb &>/dev/null

Obviously update it with the device name of your disk.

You can also vary the time based on how long your drive is idle before it powers down.