我有 2 个外部 WD Red 硬盘连接到 Raspberry Pi。
它们在 2 分钟后就开始旋转,速度快得令人恼火,我总是要等它们旋转起来。
我读过这hdparm
不适用于 WD 磁盘。我测试过hdparm -I | grep level
,没有得到任何输出。
我读过有关 的内容hd-idle
,但据我了解,它对从未进入待机状态的磁盘有帮助。
我能做什么增加待机超时?
编辑:我已经测试过hdparm -S
,零影响。
答案1
您可以编写自己的 hd-idle 版本来执行相反的操作,即在磁盘驱动器通常想要空闲之前通过对磁盘驱动器进行一些访问来保持唤醒状态。但您显然需要区分何时真正放手并让光盘进入睡眠状态。
这是使用 perl 脚本的尝试。您不需要成为 root 来运行它,但您确实需要在光盘上设置一些文件,您可以读取该文件来保持唤醒状态。与 hd-idle 一样,它会轮询来自 的光盘读/写统计信息/sys/
。当在适当的时间内没有完成任何 I/O 操作时,会使用标志从保持唤醒文件中进行少量读取,O_DIRECT
以确保完成真正的 I/O。这应该只是将读/写统计总数加 1,这样我们就可以检测下一次轮询是否也发生了其他实际 I/O。
#!/usr/bin/perl
# stop standby of idle disc which doesnt support hdparm -S 12
# for stat fields see kernel src Documentation/iostats.txt
# https://unix.stackexchange.com/a/422138/119298
use strict;
use Fcntl;
my $device = 'sda';
my $filename = '/mnt/myfs/lost+found/tickle';
# create tickle file for test. or use any readonly non-empty file
if(! -s $filename){
open(FILE,">$filename") or die $!;
print FILE "used to keep disk from sleeping\n" or die $!;
close(FILE) or die $!;
}
sysopen(FILE,$filename,O_RDONLY|O_DIRECT) or die $!;
my $minidle = 2*60; # seconds of real idle before need to tweak awake
my $maxidle = 10*60; # seconds of false idle before allow to sleep
open(STAT,"/sys/block/$device/stat") or die;
my ($lasttot,$timechanged,$done);
# create block aligned buffer for O_DIRECT read
my $bufsize = 4096;
my $align = 512;
my $buf = 'x' x ($align+$bufsize);
my $offset = unpack("J", pack "p", $buf) % $align;
$offset = $align-$offset if $offset;
while(){
my @fields = split(' ',<STAT>);
# fields: 0 reads completed ok, 4 writes completed ok. may wrap
my $tot = $fields[0]+$fields[4];
if($tot==$lasttot){
my $idle = time()-$timechanged;
print "$device idle $idle secs\n";
if($done){
# let it sleep some more
}elsif($idle>=$maxidle){ # let it really sleep now
print "$device sleep now after $idle secs\n";
$done = 1;
}elsif($idle>=$minidle){ # tickle to stay awake
sysseek(FILE,0,Fcntl::SEEK_SET)==0 or die $!;
sysread(FILE,$buf,$bufsize,$offset)>0 or die $!;
$lasttot++;
} # else builtin hardware timeout not reached yet
}else{
$timechanged = time();
$lasttot = $tot;
$done = 0;
}
seek(STAT,0,0);
sleep(55);
}
您需要将 设置$device
为光盘的名称,以及$filename
现有非空文件的名称,或可在光盘上创建的文件的名称。$minidle
我们需要光盘正常自行闲置的时间,以及$maxidle
我们希望强制其保持活动状态的时间。轮询时间在最后的
设置中。sleep()
答案2
虽然喵的回答是这个问题的正确答案,我的实际情况涉及软件袭击,而我是一个肮脏的千禧一代。
我使用写入而不是读取在 Python 中重新实现了 meuh 的解决方案。
import time
import datetime
import os
statFile = "/sys/block/<yourdevicehere>/stat"
logFile = "/some/file/on/another/drive.log"
dummyFile = "/some/file/on/drive/in/question"
updateInterval = 60 # seconds
keepAwakeTime = 30 * 60 # seconds
keepAwakeIOCount = 12 # empirically "proven"
# Clear the log file
open(logFile, "w").close()
def getIOCount():
with open(statFile, "r") as fobj:
fileContents = fobj.read()
stats = fileContents.split()
readCount = int(stats[0])
writeCount = int(stats[4])
return readCount + writeCount
# ==== main loop ==== #
maxIODiff = 0
averageIODiff = 0
diffCount = 0
previousIOCount = getIOCount()
timer = 0
while True:
ioCount = getIOCount()
if ioCount > previousIOCount:
timer = keepAwakeTime
ioDiff = ioCount - previousIOCount
if ioDiff > maxIODiff:
maxIODiff = ioDiff
averageIODiff = (averageIODiff * diffCount + ioDiff) / (diffCount + 1)
diffCount += 1
previousIOCount = ioCount
if timer > 0:
line = str(ioDiff) + " " + str(maxIODiff) + " " + str(averageIODiff) + " " + datetime.datetime.now().strftime("%H:%M:%S") + "\n"
with open(dummyFile, "w") as dummy:
dummy.write(line)
dummy.flush()
os.fsync(dummy.fileno()),
with open(logFile, "a") as log:
log.write(line)
previousIOCount += keepAwakeIOCount
timer -= updateInterval
time.sleep(updateInterval)
尽管这个解决方案在技术上不如 meuh 的解决方案正确,但我无法解析 Perl,而且它似乎在我的设置上工作得很好。我想自己编写代码。