2020年11月11日

先日新たに購入したRaspberry Pi用HDDに省電力的に回転を止める機能がなかったので自力で

今日は11月11日で「電池の日」だそうです。
11を漢字で書いたときの「十一」が、プラスとマイナスに見えるからだそう。

そういうわけで、今日は、省電力的なことを考える記事を書こうかと思います。

24時間の常時稼働をしており、うまく動いております。
しかし、ハードディスク(USB-HDD)の回転音が気になるし、触るとほんのり暖かいのも気になる。

以前まで使っていたUSB-HDDは、30分アクセスしないと自動的にディスクの回転を止める省電力(スピンダウン)機能が付いていました。
今回はこの機能が付いていません。
というわけで、この機能を自力で実装してみたくなりました。

ちなみに、USB-HDDにアクセスしなくなったらこまめにスピンダウンすればよいかというとそんなわけでなく、スピンアップの回数が多ければ故障率が高くなる(寿命が縮む)ともいわれます。

ただし、我が家のようにクーラーが付いているわけでもない部屋で常時稼働をさせていると、HDD本体の温度の高さも気になってきます(室温を超えるような温度でいさせつづけるのもまた、故障率が上がる)。

というわけで、程よく…30分間くらいアクセスされない状態が続いていたらスピンダウンする(要は今まで通り)ようにしようかなと思います。

スピンダウンには、sdparmというコマンドを使います。
これは、インストールする必要があります。

sudo apt-get install sdparm


piユーザーのホームディレクトリの下に、spdown2.sh を作り、実行権限を与えます(chmod 744 spdown2.sh)。
(後述の通り、rootユーザーで動かすものになるため、sudo chown root:root spdown2.sh してしまってもよいかも)

#!/bin/bash

# ------------------------------------------------------------------------------------
# このシェルを連続で実行した時
#   3回連続でUSB-HDDのステータスが同じなら、アクセスされていないとみなし、スピンダウン
#   4回以上連続でUSB-HDDのステータスが同じなら、スピンダウン済みと見なして何もしない
#   上記以外なら、スピンダウンすべきでないので、何もしない
# このシェルはroot権限で実行すること
# ------------------------------------------------------------------------------------

if [ "`whoami`" != "root" ]; then
  echo "Require root privilege"
  exit 1
fi

# USB-HDDのUUID
USBHDD_UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

# 初回実行の場合は、/tmp 下に状態ファイルをダミーで準備して、即終了する
if [ ! -e /tmp/hddstat1.txt ] || [ ! -e /tmp/hddstat2.txt ] || [ ! -e /tmp/hddstat3.txt ] || [ ! -e /tmp/hddstat4.txt ]; then
  echo dummy_a > /tmp/hddstat1.txt
  echo dummy_b > /tmp/hddstat2.txt
  echo dummy_c > /tmp/hddstat3.txt
  echo dummy_d > /tmp/hddstat4.txt
  exit 0
fi

# 状態ファイルのステータスを1つずつずらす
/bin/mv -f /tmp/hddstat3.txt /tmp/hddstat4.txt
/bin/mv -f /tmp/hddstat2.txt /tmp/hddstat3.txt
/bin/mv -f /tmp/hddstat1.txt /tmp/hddstat2.txt

# USB-HDDのUUIDから/dev/sd?を求める
diskid=`/sbin/blkid | /bin/grep "${USBHDD_UUID}" | /usr/bin/cut -c 6-9`
diskid0=`/sbin/blkid | /bin/grep "${USBHDD_UUID}" | /usr/bin/cut -c -8`

# 最初の状態環境変数と状態ファイルに、現在のUSB-HDDステータスを出力
/bin/cat /proc/diskstats | /bin/grep $diskid > /tmp/hddstat1.txt

# 状態環境変数を状態ファイルから取得
hddstat1=`/bin/cat /tmp/hddstat1.txt`
hddstat2=`/bin/cat /tmp/hddstat2.txt`
hddstat3=`/bin/cat /tmp/hddstat3.txt`
hddstat4=`/bin/cat /tmp/hddstat4.txt`

# 状態ファイルが 1 = 2 = 3 != 4 ならスピンダウン
# 状態ファイルが 1 = 2 = 3 = 4 ならスピンダウン済みと見なして何もしない
# 上記以外ならスピンダウンすべきでないとして何もしない

if [ "${hddstat1}" = "${hddstat2}" ] && [ "${hddstat2}" = "${hddstat3}" ]; then
  if [ "${hddstat3}" != "${hddstat4}" ]; then
    # 4回前と3回前が等しければ、スピンダウン済みと見なして何もしない
    # そうでなければスピンダウン
    /usr/bin/sdparm -r --command=stop $diskid0
  fi
fi

exit 0

なお、私の環境では /tmp はRAMドライブ(tmpfs)になっているため、10分に1回の頻度でガリガリ書いてもよくなっています。SDカードにガリガリ書くようになっている場合は、SDカードの寿命が縮まるので、やめたほうが良いです。

途中、sdparmでスピンダウンさせている個所について、hdparmを使うようになっている場合は、「hdparm -y $diskid0」とするのでよいかと思います。

やっていることは、diskstatsでディスクの状態を数値列で求め、/tmp/配下に書き込みます。
ディスクへの読み込み/書き込みが発生すれば、この数値列は変わりますが、読み込みも書き込みもなければこの数値列は変わりません。
そのため、/tmp/配下に書き込んだ数値列が30分間変わらなければ、読み込みも書き込みもなかったとみなせることになりますので、スピンダウンします。

なお、diskstatsのどの行を見ればよいかを判定する目的と、スピンダウンするコマンドへのパラメータを指定する目的で、デバイス名(/dev/sd?)を求めておく必要があります。これはblkidコマンドで行いますが、元ネタとしてHDDのUUIDを求めておく必要があります。UUIDは、「XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX」としている個所に書き込みます。

(UUIDを求めるには、「今の時点で /dev/sda に繋がっているものはどれだろう?」という感じで、上記のblkidコマンドで逆引きするのがよいかと思います)


で、上記のシェルスクリプト(/home/pi/spdown2.sh)が10分に1回の頻度で呼び出されるようにします。
rootのcronに登録するのが良いかと思います。

rootのcronの設定を編集
sudo crontab -e

cronの設定の中身に追加
# HDDが30分間使われていなければスピンダウンする(10分ごとのチェックを3回)
*/10 * * * * /home/pi/spdown2.sh

これで、Raspberry Piに繋いだUSB-HDDが30分間の未使用でスピンダウンするようになりました。

なお、前にも書いた通り、頻繁に、こまめにスピンダウンすればよいというわけではありません。その分、こまめにスピンアップが発生してしまうようであれば、HDDの壽命が逆に縮みます。

posted by ayacy at 00:00 | Comment(0) | TrackBack(0) | PC
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
※ブログオーナーが承認したコメントのみ表示されます。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/188104021
※ブログオーナーが承認したトラックバックのみ表示されます。
※言及リンクのないトラックバックは受信されません。

この記事へのトラックバック