はじめに
2008年4月某日、所属する研究室のファイルサーバの挙動がおかしくなる。lsコマンドを叩いてもディレクトリが表示されない。ついでにI/Oエラーなぞ出してくれやがったりする。嗚呼。その時点で確信をしたことといえば、『HDDが逝ってしまわれた』ということ、年度の変わり目に色々と更新したデータの復旧作業が待っているということだった。
壊れた直後の状態
とりあえず、研究室のサーバ室で実際の状況を確認。異音はしていなかったが、I/Oエラーが出ていたのは事実で、dmesgにもあまり見たくもないログが残っていた。エラーを吐いたのは2つのディスクで、各種ドキュメントの保存に使っていたものと/homeのような個人用途向けに配置したもの。この時点ではまだクラッシュした原因が不明で、かつHDDが物理的に壊れたというわけでもなさそうだったので、これ以上アクセスされないためにも一旦この2つのディスクをアンマウントする。
ログを眺めてみたものの、I/Oエラーという文字ばかりがつらつらと表示され、特にこれといった障害らしき障害報告が見あたらない。以前、自宅PCのHDDが物理的に逝った時もI/Oエラーが出ていたが、あの時は誰もが気づくくらいの爆音でヤバイ音を奏でていた。あの時はHDDの寿命で物理障害を起こしたのが原因だったが、今回のそれは異音もなく、特に物理障害の原因らしき何かも思いつかない。埒があかないので、危険を承知で読み込み専用でマウントし直してみる。
# mount -o ro /dev/sda1 /mnt/tmp (復旧を考えるなら無闇にマウントするべきではないので注意)
本当なら先にddでディスクイメージをちゃんととることが大切(その事実に思い至ったのが復旧作業を始めてからだったのだが)。この時点で分かったことは、原因は不明だが、/dev/sda1と/dev/sdb1のツリー構造が入れ替わってしまっているということだった。もともと/dev/sda1に割り当てていたラベル(DISK1とする)が/dev/sdb1に割り当てていたラベル(DISK2とする)に書き換えられており、逆に/dev/sdb1は/dev/sda1のラベルに書き換わっていた。無論、中のデータそのものは入れ替わっていないはずなので、どうもファイルテーブル構造が壊れたと考えるのが妥当と思われる。別段そんなディスク構造を弄るような操作はしてなかったのでウィルスか何かかと思ったが、それにしてもそこだけピンポイントに破壊するウィルスや他に異常が生じているということもなく、その他のログも侵入を検知していなかったので、やはり単純にHDDが壊れただけと考えるほうが自然なのだが。
クラッシュした原因
当初は先に復旧作業に移り、あまり原因について深く考えていなかったが、ひょんなことから原因と思われる事態が発覚した。それは、HDDに接続していたUPSのバッテリーにあった。どうやらバッテリーの消耗・寿命によると思われる電圧の不安定化により、接続していたHDDがやられてしまったらしい。電圧不安定も常に不安定というわけでなく、何らかのタイミングで不安定化していたようで、HDDへ書き込むタイミングと重なればディスクの構造が破壊されることも有り得る(現にUPSを取り替えた現在では、同じI/Oエラーは生じていない)。今回壊れた2つのディスク両方、その不安定化したUPSに接続していたので、壊れた原因は電源の問題であろうということで、とりあえず納得がいった。
ただ、実際にはこの事実に気づくのが遅れてしまい、バックアップをとっていたほうのディスクまで構造が壊れ、一時は本当にゼロから復旧になるかと肝を冷やしたこともあったが……。
復旧前の準備
実際に復旧作業の手順を紹介する。復旧は試行錯誤であったが、それら全てを載せるわけにもいかないので復旧に必要な部分だけを要約して記述しておく。ここで大事なことは、壊れたディスクそのものに復旧作業を試さないこと、データがある限りは諦めないことである。後者はともかく、前者の意味は常にディスクイメージのオリジナルをとっておくことを意味する。復旧で用いるfsckは、ヘタをすればより一層ディスクを破壊しかねない。まず壊れたディスクのイメージを抽出することが何よりも先に行うべきことであり、以降はこのディスクイメージに対して復旧作業を行う。そうすることで、もし致命的な失敗を犯しても、イメージがある限り何度もやり直せるからである。無論、オリジナルのディスクも、復旧が完了するまでは大切に保管しておく。
ディスクイメージの抽出にはddを用いる。このコマンドは非常に強力なもので、コマンドにミスがあると起動しているOSごと破壊しかねないので、使用の際には十分注意すること。壊れて復旧を行うディスクを/dev/sda1として接続している。
# dd if=/dev/sda1 of=/mnt/tmp/broken.img ibs=512 obs=1024k conv=noerror,sync count=488279610
ddコマンドを用い、/dev/sda1からイメージを/mnt/tmp/broken.imgとして吸い出している(/mnt/tmpには容量の十分大きなディスクがマウントしてある)。このとき、ibs=512とすることと、conv=noerror,syncとすることが重要な点。こうすることで、ディスクの読み込めない=破壊された部分をゼロで埋め、それ以外の部分をサイズ通りに読むことが出来る。countはどのくらいの量で読み込みを行うかを指定するもので、ディスク全体を指定するのであれば、HDDのヘッダ・セクタ・シリンダ数の積を求めて指定すればよい。fdiskコマンドで確認することが出来る。
# fdisk /dev/sda コマンド (m でヘルプ): p Disk /dev/sda: 250.0 GB, 250000000000 bytes 255 heads, 63 sectors/track, 30394 cylinders Units = シリンダ数 of 16065 * 512 = 8225280 bytes (略)
このとき、このディスクのヘッダは255、セクタは63、シリンダは30394である。ゆえに、255*63*30394=488279610を指定する。この値に512を掛けると249,999,160,320 byte、約250GBで一致する。ただしここまで書いておいてなんだが、最近のddではcountを指定しなくてもパーティションの終端でしかりと終わってくれるので、実はcountを指定しなくても正常にイメージが吸い出しできる。countなしでやってみて、明らかに失敗(ディスクサイズよりもイメージのファイルサイズが明らかに食い違っている等)している時はcountをつけてやってみることを勧める。
以上で復旧用にディスクイメージの吸い出しを行うことが出来るが、このことから分かるように吸い出し先には最低でも壊れたディスクと同等の容量を持つHDDが必要になる。さらにディスクイメージを貼り付け、fsckや各種復旧ソフトで復旧を行うために、同容量のディスクが要る。つまり、安全に復旧させるためには、壊れたディスクの二倍以上の容量を持つHDDか同容量のHDD2台が必要ということである。
ディスクの吸い出しにはかなりの時間がかかる(250GBの吸い出しで数時間〜十数時間程度)。吸い出しが完了したら、壊れたディスクは電源を落として外しておく。以降の試行錯誤はイメージのみで行う。
/mnt/tmpにマウントしている/dev/sdc1、復旧を行う作業スペースとして/dev/sdd1を確保する。/dev/sdd1の大きさは壊れたディスクと同じにしておく(fdiskによって同シリンダ数を指定して確保できる)。fdiskで作業スペースを確保したら、今度はbroken.imgを/dev/sdd1に流し込む。
# dd if=/mnt/tmp/broken.img of=/dev/sdd1 bs=1024k
次はconvオプションも要らず、読み込み・書き込み速度も1024kとしてbs=1024kで構わない。イメージの書き込みは250GB程度なら数時間で終了する。もし以降の復旧手順でミスをしても、イメージから書き込んでやり直せば幾らでも修復できる。
fsckによる復旧
ファイルシステムチェック(fsck)によって、ファイルシステムの復旧を行う。これを直接、壊れたディスクに対して実行することが禁忌とされるのは、このfsckがHDDに対しかなりの負荷を強いるからである。論理障害ならともかく、物理障害の起きているHDDにこのfsckをかけてしまうと、直るはずのものも直らないどころか、二度と起動しなくなることもままあるので絶対にやってはいけない。無論、バックアップの意味もあるので、論理障害でも別のディスクにイメージを吸い出してからfsckを行うのがセオリー。
fsckで、対象となるディスク(ここではイメージを貼り付けた/dev/sdd1)を指定し、まず正常にfsckが実行できるか確認する。
# fsck -n /dev/sdd1
-nを指定することで、何も処理を行わずにチェックの行程だけを確認できる。この時点でスーパーブロックが読み込めない、または実際にfsckを始めてみて無限ループする場合などは、スーパーブロックのバックアップを用いてfsckを実行する。スーパーブロックのバックアップはmkfsを行った時に表示されるのだが、基本的に32768を使うのでこれを試すのが良い。32を使用することもある。
# fsck -n -b 32768 /dev/sdd1
これでうまくいきそうであれば、-nオプションを外し、-yオプションを指定して実際に修復を行う。
# fsck -y -b 32768 /dev/sdd1
システムの修復にも相当時間がかかる。終了したら読み取り専用でマウントを実行してみる。
# mount -o ro -t ext3 /dev/sdd1 /mnt/tmp2
運良く壊れずに済んだものは以前の通りに配置されているはずだが、壊れたファイルやディレクトリはlost+foundに格納されている。ファイル名が欠落しinodeの番号がファイル名となっているので、ファイルサイズや更新日付、ディレクトリ構造などから中身を推測して復旧作業を行う。このとき、findを用いると便利である。
# find lost+found -type d (ディレクトリのみを表示) # find lost+found -type f (ファイルのみを表示) # find lost+found -mtime -60 (更新日付が60日前までのものを表示) # find lost+found -size +100k (ファイルサイズが100KB以上のものを表示)
通常のツリー構造になく、lost+foundにもない場合は、ファイルが壊れて修復できなかった・消えてしまったということである。もしどうしても復旧したいファイルがあり、その拡張子が分かっていれば次の復旧ソフトなどで復旧できる可能性はある。
復旧ソフトを用いた復旧
fsckではファイルが見つからない、もしくは壊れてしまっていてどうしようもない、という場合には復旧ソフトを使って復旧することになる。この復旧ソフトとして有名なものはファイナルデータなどがあるが、一般企業の製品であるので使用するには無論使用料が必要となる(無料体験版でのチェックは可能)。個人的にはまずPhotoRecの使用を勧める。日本語は使えないが、オープンソースソフトなので使用料金がかからず、対応するファイルの種類と利用可能なシステムが圧倒的に多いというのが特徴。FAT/NTFS/HFS+/EXT2/EXT3と、Win/Mac/Linuxのメジャーなファイルシステムに対応しているのが魅力。実際に使用してみた感じでは、そこらの復旧ソフトと比較しても何ら遜色なく動作してくれる。上記fsckでの復旧に失敗したファイルを、PhotoRecで復旧させたという経験もあるので性能も良い。PhotoRecでダメという判断をしてから、ファイナルデータでの無料体験版のチェックや購入を考えても遅くはない。
基本的に、PhotoRecを起動させてしまえばあとは手順に従っていくだけで復旧を行うことが出来る(GIGAZINEさんの記事参照)。対象となるのは/devで認識されるディスクで、パーティション単位のスキャンやディスク全体のスキャンも行える。復旧させたいファイルの拡張子が分かっていれば、その拡張子だけに絞って復旧させた方が無論早く終わる。ちなみに、Microsoft Office 2007以降のOOXML(docxなど)や、OpenOffice.org 2.0以降のODF(odtなど)などはZIP形式で圧縮されているので、拡張子にはzipを指定する。同様に、xls/pptなどのMS Officeのファイル形式はdocとしてまとめられているなど、幾つかの拡張子は別の拡張子と一緒にスキャンされるということに注意。デフォルトの検索設定で検索するとそれこそ大量のファイルが復旧されるので、この復旧においても復旧先は元と同容量程度の作業スペースを確保しておきたい。
fsckをかけて修復した後のディスクに対して実行するのも構わないが、もしそれでも復旧できないようであれば、fsckをかける前の状態のディスクに対して実行してみるのも良い。fsckで無闇に構造が弄られてないので、むしろfsck後よりも復旧率が上がる可能性もある。実際、fsck後では見つからなかったドキュメントが、fsck前のディスクからは復旧できたということもあった。
その他、USBメモリや幾つかのデジカメにも対応しているので、間違えてそれらをフォーマットしてしまった時にも復旧させられるツールとして利用することが出来る。
結果
電源不良のため、最終的にディスクの構造が壊れてしまったものが3台。うち1台は残り2台のバックアップに使用していたものだったので、その中にあるバックアップファイルが取り出せなければ悲惨なことになるところだった。バックアップファイルは140GBくらいだったが、これはfsckで無事に復旧。ファイルサイズが大きいからといって壊れやすいわけではない。だがスーパーブロックが逝かれてしまっていたらしく、fsck時に無限ループにはまってしまったこともあった。一応時間がかかるものかと我慢したが、さすがに一週間もfsckが終わらないのはおかしい。100GB前後なら24時間程度、長くても48時間以内に終わっていなかったらfsckの失敗を疑うべき。-bオプションで32768を指定してfsckしたらあっさりとうまくいったので、たぶんとばされたのはスーパーブロックの領域だったんだろう。
3月に更新したばかりのファイルはまだフルバックアップに入っておらず、ディスク復旧前に四方八方へと手を尽くしてみたが、どうしても他の場所から復旧できないドキュメントが7つあった。fsckでも復活できず、その後にPhotoRecで探しても見つからず。諦めようかとも思ったが最後の手段としてfsck前の状態のディスクにPhotoRecを試してみたら存外うまく実行できたこと、そして無事7つとも復旧できたことは望外の喜びだった。
これらに懲りて、ディスクをRAID化、フルバックアップのルーチン化、最重要ファイルのDVDバックアップ、というファイルのバックアップ体制を強化したことは言うまでもない。知識と技術は身に付いたが、願わくばもう使うことがないように。
参考サイト
- 2002/11/07 自宅(1) 「復活の日: FreeBSD ディスククラッシュ事件総括」(不定期性写真日記)
- 壊れたHDDからデータを取出す方法(ぴょぴょぴょ?)
- あるext3復旧レポート(nemuiDoc)
Comment