読者です 読者をやめる 読者になる 読者になる

unsuitanの日記

パソコンの神様 公式ブログ!

HDDが壊れそうなときにdd使うのは古い。というわけでGNU ddrescue

こちらのWebサイトは移転しました。


超高速落下

HDDが壊れかけたときのデータ救出法です。

 

■経緯

・録画サーバの一次保存HDD(Seageteの1TB玉)にあるデレマスを見てたら突然readが不安定になった。dmesgとかSMARTとか見たらread errorが多発してた。

老害なのでddで吸い出したら494GBで引っかかる。「conv=sync,noerror」を付けても1時間で3MBしか進まないという素敵な状況。

・イマドキの時代、read error出たらサクッと諦めて次のセクタに進む吸い出しソフトないの?

 

■そんなわけで

老害だから知らなかった「ddrescue」なるソフト。だって死にかけのHDDを吸い出すのって多分十数年ぶりだぜ。

世の中には「GNU ddrescue」と「dd_rescue」の2種類があるそうですが、ここで扱うのは「GNU ddrescue」です。

www.gnu.org

 

 

■つかいかた

普通にconfigure→make→make  installで入れる。

その後はこちらのサイト参照。

GNU ddrescue のあれこれ

 

「んじゃなんでお前ブログ書いてるんだよ」と仰るのはごもっともなんですが。

この貴重な資料、Geocitiesに置いて放置されてるんですよね…Geocitiesの将来を考えると「書いておいた方がいい」と思った次第。

 

GNU ddrescueのここがスゴイ

・read errorが発生したらガン無視スキップしてくれて(吐き出し先はゼロパディングらしい)、不良セクタの位置がロギングされる

・一旦全部書き出した後、ログに残った不良セクタだけを決め打ちでリトライできる

・もはや人類には不可能な「どのファイルが不良セクタの被害を受けたか」を調べられる

 

どれをとっても非常にありがたい機能です。

 

■実作業

以下の条件で行いました。

・CentOS6

・壊れかけのHDD: /dev/sdb (sdb1がext4)

    (NTFSな人は吸い出した後で各自工夫してください)

・直接別のHDDにdd的に吐けるけど、今回はファイルサーバにファイル(/mnt/fs/back.img)として吐き出す

・ddrescueのログは/mnt/fs/ddrescue.logに吐き出す

・吐きだしたイメージ(/mnt/fs/back.img)は、うまくいったら/mnt/imageにmountする

 

 

基本書式は

ddrescue [オプション] [読込元] [書き出し先] [ログ出力先]

です。書き出し先はファイルでも直デバイスでもOK。

直デバイスに書き出す人はHDDの指定を間違えないよう気をつけてください。

 

まず初回はread errorを無視するモード(-n)で読みます。-vは進捗詳細表示。

パーティションはmountさせてません。

------

# ddrescue -n -v /dev/sdb /mnt/fs/back.img /mnt/fs/ddrescue.log

------

 

進捗がこんな感じで表示されて、終わったらこんな感じ。

1TBで1.65日かかった。エラーは意外と少ない。100MB切ってる。

------

rescued:     1000 GB,  errsize:  92286 kB,  current rate:        0 B/s
   ipos:   999370 MB,   errors:     819,    average rate:    7011 kB/s
   opos:   999370 MB, run time:    1.65 d,  successful read:       2 s ago
Finished

------

 

次にエラー箇所だけ読みます。

-dはダイレクトアクセス、-fはoverwrite、-r3は「3回リトライ」で増やしたい人は増やしてください(でも増やしすぎると死にかけのHDDに負荷がかかる)

------

# ddrescue -d -f -r3 -v /dev/sdb /mnt/fs/back.img /mnt/fs/ddrescue.log

------

 

結果です。

errorsの数が変わってないので、ダメなモノはダメだった模様。

------

Current status
rescued:     1000 GB,  errsize:  92286 kB,  current rate:        0 B/s
   ipos:   999370 MB,   errors:     819,    average rate:        0 B/s
   opos:   999370 MB, run time:    1.93 m,  successful read:    1.93 m ago
Finished 

------

 

では保存したファイル(/mnt/fs/back.img)を/mnt/imageにmountしてみましょう。

------

# mount /mnt/fs/back.img  /mnt/image
mount: you must specify the filesystem type

------

 

loopbackじゃないとダメな模様。あれ?

------

# mount -o loop /mnt/fs/back.img  /mnt/image
mount: you must specify the filesystem type

------

 

先頭セクタの位置がなんかズレてるようです。

fdiskないしpartedで該当パーティションの開始位置(セクタ)を確認します。

------

・fdiskの場合

 # fdisk -lu /mnt/fs/back.img

(中略)

          Device          Boot      Start         End            Blocks       Id  System
/mnt/fs/back.img      1          63     1953520064   976760001   83  Linux
Partition 1 has different physical/logical endings:
     phys=(1023, 254, 63) logical=(121600, 254, 63)

 

・partedの場合

 # parted /mnt/fs/back.img

(parted) unit s

(parted) p

モデル:  (file)

ディスク /mnt/fs/back.img

セクタサイズ (論理/物理): 512B/512B

パーティションテーブル: gpt

 

番号  開始         終了         サイズ       ファイルシステム  名前  フラグ

1    63s       953520064s      1953520001s       ext4              zfs

------

 

というわけでmountするのにセクタの先頭位置のオフセットが必要です。

オフセット量は「Startの値 * 512」(この場合は63 * 512 = 32256)です。

------

# mount -o loop,offset=32256 /mnt/fs/back.img /mnt/image/

------

 

mountできたら/mnt/image内のファイルを新しいHDDにコピーしちゃってください。

これでデータ救出は完了です。

 

コピーが終わったら、このイメージを使って「どのファイルに不良セクタが当たってたか」を調べます。

 

やってることは以下の感じです。

 

不良セクタとしてロギングされた位置に、任意の文字列を書き込む

・findとgrepを使って、ひたすらファイル内を文字列検索する

 

力業だなあ…

というわけでデータを書き換えるんですが、元に戻せます(後述)

 

要はgrepなので置き換え文字列は「元データとかぶらない文字列」にする必要がありますが、参考にしたサイトは文字列を「DEADBEEF」にしてました。

俗に言うHexspeak(16進数で単語を作る)ってやつです。

Hexspeak - Wikipedia

 

んじゃうちは「FACEFEED」にします(AlphaのWindows触ってみたかったなあ)

この文字列は一旦ファイル(/mnt/fs/tmpfile)に入れます。

あとイメージをmountしたままなので、一旦umountします。

------

printf "FACEFEED" > /mnt/fs/tmpfile

umount /mnt/image

------

 

不良セクタを文字列(FACEFEED)で置き換えます。

------

ddrescue --fill=- /mnt/fs/tmpfile  /mnt/image/back.img /mnt/image/rescue.log

------

 

6秒であっという間に終わります。100MBないし。

------

filled size:    92286 kB,  filled areas:    819,  current rate:    5050 kB/s
remain size:         0 B,  remain areas:      0,  average rate:   15357 kB/s
current pos:   999370 MB,  run time:        6 s
Finished

------

 

終わったらtmpfileを待避させ(させる理由は分からんが必要なくね?)、もう一回イメージをmountして、ひたすらgrepします。teeで出力をファイルとコンソールの両方に向けるとよいでしょう。

------

# mv /mnt/fs/tmpfile /var/tmp

# mount -o loop,offset=32256 /mnt/fs/back.img /mnt/image/

# find /mnt/image -type f -exec grep "FACEFEED" '{}' ';' | tee /mnt/fs/find_broken_file.log

------

 

出力はこんな感じです。この子たちが被害を受けました。

------

バイナリー・ファイル/mnt/image/3542-21-20150308-1700-22.m2tは一致しました
バイナリー・ファイル/mnt/image/3551-21-20150305-0229-25.m2tは一致しました
バイナリー・ファイル/mnt/image/3615-10-20150315-0030-161.m2tは一致しました
バイナリー・ファイル/mnt/image/3597-7-20150219-0000-211.m2tは一致しました
バイナリー・ファイル/mnt/image/3546-21-20150313-0120-21.m2tは一致しました
バイナリー・ファイル/mnt/image/3596-9-20150315-0030-211.m2tは一致しました
バイナリー・ファイル/mnt/image/3633-7-20150305-0230-141.m2tは一致しました
バイナリー・ファイル/mnt/image/3596-10-20150315-0030-16.m2tは一致しました
バイナリー・ファイル/mnt/image/3518-22-20150315-0800-24.m2tは一致しました
バイナリー・ファイル/mnt/image/3616-23-20150320-2300-211.m2tは一致しました
バイナリー・ファイル/mnt/image/3631-6-20150221-0120-21.m2tは一致しました
バイナリー・ファイル/mnt/image/3548-25-20150321-0157-22.m2tは一致しました

------

 

書き換えた箇所を元に戻したい人は、umountして以下をどうぞ(ゼロパディングしてるだけなんですが)

------

umount /mnt/image

ddrescue --fill=- /dev/zero  /mnt/image/back.img /mnt/image/rescue.log

------

 

 

 

ファイルはfoltia anime lockerで録画したTSなんで、何のアニメかはうまく探してあげてください。

でも850GBもあるアニメを全部見てエラーチェックやるよりよっぽどマシでございます。

被害はたいして興味が無かったアニメばかりでよかったです。