WD_SOFTBADSECTオプション
不幸にして職場で作業に使用しているPCのハードディスクが不調となったのですが、NetBSDのATAなハードディスクのドライバーwd(4)のWD_SOFTBADSECTオプションが役立ったというか、動作を検証する経験をしたので書いてみます。
問題のハードディスクは不良セクターが40くらい発生していて、負荷を掛けて多少増えたかもしれない状況です。
WD_SOFTBADSECTの詳細
あまり知られていませんが、NetBSDのwd(4)にはWD_SOFTBADSECTというオプションがあって、発生した不良セクターをソフトウェア、つまりドライバー側で対処する機能があります。
同様な試みには bad144(8) というコマンドが古くからあって、DEC standard 144 bad sector という今時は誰も知らない(私も名前の由来は知らない)方法でで不良セクターをソフトウェア的に管理します。ところが、これはハードディスクの伝統的なシリンダー、ヘッド、(トラックあたりの)セクター数といった配置を前提としています。いわゆるCHSによるセクターのアドレッシングですが、bad144(8)はこれに依存していて論理セクターアドレスでないと足りない今時のハードディスクでは事実上使用できません。
bad144(8)は所定の形式で不良セクターの情報を物理的にハードディスクに記録しますが、対照的にWD_SOFTBADSECTオプションは名前のようにソフトウェア的に処理を行います。つまり、ドライバー内で不良セクターのリストを用意して、エラーが起きたセクターを記録して、さらなるアクセスを避けるといった目的に使用しています。(と、思います。)
dkctl(8)
発生した不良セクターのリストは、dkctl(8)というシステムコマンドで状況を確認できます。dkctl(8)はディスクのパーティションのドライバーdk(4)を制御するシステムコマンドですが、この他にハードディスクの内蔵キャッシュの制御なども行います。
WD_SOFTBADSECTオプションをカーネルで有効にしていると、不良セクターのリストの管理も可能です。サブコマンドのbadsectorでflush, list, retryを指定できます。
不良セクターの確認
今回、実際に不良セクターが発生した後で、その様子をbadsector listで確認すると次のようになります。
# dkctl wd1 badsector list
/dev/rwd1d: blocks 1903708656 - 1903708783 failed at Fri Mar 16 12:22:55 2012
/dev/rwd1d: blocks 1903707504 - 1903707631 failed at Fri Mar 16 12:22:33 2012
/dev/rwd1d: blocks 1903707627 - 1903707627 failed at Fri Mar 16 12:00:55 2012
/dev/rwd1d: blocks 1903707626 - 1903707626 failed at Fri Mar 16 12:00:36 2012
/dev/rwd1d: blocks 1903707625 - 1903707625 failed at Fri Mar 16 12:00:17 2012
/dev/rwd1d: blocks 1903708688 - 1903708688 failed at Fri Mar 16 11:59:59 2012
不良セクターの再確認
不良セクターのリストに含まれる内容をbadsector retryで再度確認してみます。
# dkctl wd1 badsector retry
/dev/rwd1d: bad sector clusters 6 total sectors 260
/dev/rwd1d: bad sectors flushed
/dev/rwd1d: Retrying 1903708688 - 1903708688
/dev/rwd1d: block 1903708688 - failed
/dev/rwd1d: Retrying 1903707625 - 1903707625
/dev/rwd1d: block 1903707625 - failed
/dev/rwd1d: Retrying 1903707626 - 1903707626
/dev/rwd1d: block 1903707626 - failed
/dev/rwd1d: Retrying 1903707627 - 1903707627
/dev/rwd1d: block 1903707627 - failed
/dev/rwd1d: Retrying 1903707504 - 1903707631
/dev/rwd1d: block 1903707504 - ok
/dev/rwd1d: block 1903707505 - ok
... (中略) ...
/dev/rwd1d: block 1903708779 - ok
/dev/rwd1d: block 1903708780 - ok
/dev/rwd1d: block 1903708781 - ok
/dev/rwd1d: block 1903708782 - ok
/dev/rwd1d: block 1903708783 - ok
#
実際には読めたセクターがリストから除かれていますので、もう一度確認すると確かに減っていることがわかります。
# dkctl wd1 badsector list
/dev/rwd1d: blocks 1903707627 - 1903707627 failed at Fri Mar 16 12:40:00 2012
/dev/rwd1d: blocks 1903707626 - 1903707626 failed at Fri Mar 16 12:39:41 2012
/dev/rwd1d: blocks 1903707625 - 1903707625 failed at Fri Mar 16 12:39:22 2012
/dev/rwd1d: blocks 1903708688 - 1903708688 failed at Fri Mar 16 12:39:03 2012
姑息な秘密兵器
ここで標準のdkctl(8)にはない秘密兵器を使ってみます。といってもエラーが起きたセクターに対して書き込みを行った上で、badsector retryを再度行う姑息(だけど役立つかもしれない)な技です。
# dkctl wd1 badsector rewrite
/dev/rwd1d: bad sector clusters 4 total sectors 4
/dev/rwd1d: bad sectors flushed
/dev/rwd1d: Retrying 1903708688 - 1903708688
/dev/rwd1d: block 1903708688 - ok
/dev/rwd1d: Retrying 1903707625 - 1903707625
/dev/rwd1d: block 1903707625 - ok
/dev/rwd1d: Retrying 1903707626 - 1903707626
/dev/rwd1d: block 1903707626 - ok
/dev/rwd1d: Retrying 1903707627 - 1903707627
/dev/rwd1d: block 1903707627 - ok
# dkctl wd1 badsector list
#
不良セクターに対して書き込みを行うと、ATAなハードディスクは代替セクターの割り当てを行う機能があります。ここでは、それが働いて見かけ上不良セクターがなくなったように見えます。
もっとも、今回のハードディスクは別途atactl(8)のsmart statusで確認すると、S.M.A.R.T.の代替セクターの数が増えていません。これは、やはり何か問題なので早々に交換しなければならないでしょう。
dkctl rewriteの修正
dkctl rewriteの修正は長らく手元に置いていたものでsend-prしたようなぁ、と思っていたらなかったかもしれません。
Copyright © 2011-2024 Takahiro Kambe all rights reserved.