USB硬盘的固定设备名和自动休眠
AirPort Extreme可以外接USB硬盘提供文件服务,但是和它的路由功能一样,都不够满足我的需求。而作为穿墙路由器的华硕小机器有4个USB口,我还用它兼作文件服务器使用,提供Samba和NFS。
但是Gentoo在这里遇到两个小问题。
第一个问题,USB硬盘是可以热拔插,这样由于载入顺序的问题,每个硬盘设备名称可能会变化。例如这个机器自带一个读卡器,在没有外挂USB硬盘时启动后候设备名为/dev/sdb。之后插入USB硬盘,USB硬盘的设备名为/dev/sdc。但是如果挂着USB硬盘启动,这两个设备的设备名就正好反过来了。我希望是固定的设备名。
第二个问题,USB硬盘长时间不访问的时候不会自动停下来,这样既不省电也不利延长硬盘的寿命。我希望在不用的时候它可以休眠。
设备名的问题可以用udev的rules解决。我加了一个udev配置文件/etc/udev/rules.d/99-external-storages.rules。
KERNEL=="sd*", SUBSYSTEMS=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="0158", ATTRS{serial}=="20071114173400000", SYMLINK+="cardreader%n"
KERNEL=="sd*", SUBSYSTEMS=="usb", ATTRS{idVendor}=="1bcf", ATTRS{idProduct}=="0c31", ATTRS{serial}=="20090717090A", SYMLINK+="storage/neso%n"
这样给内置的读卡器添加了一个设备名的符号链接/dev/cardreader;给我的NESO 1T硬盘添加了设备名符号链接/dev/storage/neso。用固定名称访问设备的问题就解决了。
第二个问题稍微复杂些,一直没找到方便的方法。laptop-mode-tools也没能满足我的要求。一番搜索后找到sdparm可以用来控制USB硬盘,还有一段perl脚本用来调度sdparm。这样就可以满足我的需求了。脚本的原始出外我给忘了,这里我稍微修改了一点,增加对设备名符号链接的支持。
#!/usr/bin/perl -w
use File::Basename;
use Cwd 'abs_path';
$statfile = "/proc/diskstats";
die "$0: Cannot read $statfile\n" unless -r $statfile;
$| = 1;
($disk, $interval) = (@ARGV);
if (-l $disk) {
$original_disk = $disk;
while (-l $disk) {
$disk = readlink $disk;
}
$disk = dirname($original_disk) . "/" . $disk;
$disk = abs_path($disk);
}
$disk =~ s,/dev/,,;
print "$0: disk: $disk, interval: $interval\n";
$halted_data = $last_seen = '';
while (1) {
open(STATUS, $statfile);
($_) = grep(/^\s+\d+\s+\d+\s+$disk\s/o, <STATUS>);
close STATUS;
if ($last_seen eq $_ && $halted_data ne $_) {
print "Spinning down: $disk\n";
system "sync";
system "sdparm", "--command=stop", "/dev/$disk";
$halted_data = $_;
}
$last_seen = $_;
sleep $interval;
}
最后在启动脚本里加上
ebegin " - Spindown USB HD"
nohup /usr/local/sbin/spindown-usbhd /dev/storage/neso 1200 >> /var/log/spindown-usbhd.log 2>&1 &
eend $?
好了,20分钟这块硬盘没有读写之后自动休眠。