ttt

getttyent

(FreeBSD) ddコマンドでパーティションまるごと高速コピー・・・しようとして、ちょっとハマった

2007-09-10 23:33:25 | デジタル・インターネット

どうやらハードディスクが壊れているらしいので、新しいハードディスクを買ってきました

Windowsを新規インストールする時間と手間が惜しいので、FreeBSDのddコマンドで、ハードディスクのパーティションをまるごとコピーすることにしました。初心者には、あんまりお勧めできない方法なんですが。

Windowsの場合、というかどのOSでも普通はそうなんですけど、OSとして使用中のパーティションの内容(Windowsなら、Cドライブなど)を、別ディスクに正確にコピーすることはできません(昔、Macintoshでは、当たり前のようにできたんですけど・・・)。

別の起動ディスクでブートさせて、コピーする場合でも、ブートローダがきちんとコピーできない場合があったり、それに、ファイル単位でコピーするので、ランダムアクセスに近い挙動をするので、それなりに時間がかかります。

一方、ddでセクタ単位でコピーする場合は、シーケンシャルアクセスになるので、データ転送速度は、ドライブの限界までだせるので、短時間でコピー作業が完了します。

ただし、ddでコピーする場合の欠点としては、もしもコピー元ディスクに不良セクタ(bad sector)があるときは、どのファイルが壊れたのかわからないままコピーされる、という、なんだかなぁ~、な結果になります。壊れてるんだから仕方ないですが。

作業手順としては、だいたいこんな感じでしょうか。

  1. コピー先の新HDDに、コピー元とまったく同じ大きさのパーティションを切る
  2. ddで、パーティションをまるごとコピーする
  3. コピー先の新HDDのMBRにブートローダをインストールする。

・・・という感じですが、なんだか、今回、いろいろとはまったので、失敗したことのメモを残しておきます。あんまり参考にならない話です。


● sysinstallコマンドでパーティションを切ろうとしたら、うまくいかなかった。なぜ?

sysinstallを実行して、Configureを選択、Fdiskを選択します。そして、コピー先の、新しいディスクを選択。

200709101


いつもそうなんですが、ジオメトリが変だから無視してそれっぽい値を使うよ、といわれます。とりあえず今は、まあいいや、と思うことにします。

200709102


おっと、その前に、あらかじめ、コピー元のディスクのパーティションを、fdiskコマンドで調べておきます。「fdisk ディスク名」、たとえば、「fdisk ad0」とかで、表示されます。

200709103

1つめのパーティションサイズは、32772537セクタでした。

そこで、sysinstallのFDISK Partition Editorで、このセクタ数、32772537を入力してやります。

200709104


つづいてパーティションタイプを指定しますが、コピー元のタイプが7だったので、7を指定します。

200709105


これで新たにパーティションが作成されるのですが(実際には、まだディスクに書き込まれていない)、なぜか、サイズが32756472になっていて、さっき指定したサイズとは違っています。

200709106


昔からのUnixユーザーなら、すぐに、「ははぁ~ん、シリンダ境界にあわせて、パーティションサイズを自動的に調整したんだな」とか思うんでしょうが、

32756472 / 63 / 255 = 2038.9960784313

・・・割り切れないじゃないですか。ぜんぜんシリンダ境界になってません。

ちなみに、

32756472 / 63 = 519944

なので、トラックあたりのセクタ数でなら割り切れるんですが、それなら、

32772537 / 63 = 520199

でもあるので、もともと入力した数も割り切れます。これ、何なんでしょうね?

いまどきのHDDの場合、トラックごとにセクタ数が違ってたりするらしいので、シリンダ境界に合わせるのは、たぶん、あまり意味ないと思います。だいたい、ヘッド数が255なわけないですし。

ということで、sysinstallを使うのはあきらめて、fdiskコマンドで、全部、数値を手入力して、まったく同じサイズのパーティションを作ってやりました。

ようするに、「fdisk -i ad0」とかやって、ちまちまと、全部の数値を、コピー元パーティションとまったく同じになるように、入力してやりました。

sysinstallがうまく使えなかった件は、ちょっと悔しいです。今度、sysinstallのソースでも眺めてみようか。


● ddでコピーしたのに、なぜか正常にコピーされなかった

基本的に、ddでコピーするときは

dd if=コピー元パーティション of=コピー先パーティション bs=ブロックサイズ

みたいな書式で指定するようになっていて、ブロックサイズは、本当は512(バイト)なんですが、大きめの値を指定すると、データ転送速度が上がるので、今回の場合、1Mバイトとして、

dd if=/dev/ad10s1 of=/dev/ad14s1 bs=1m

みたいにやってみたのですが、これは、今回の場合、ダメでした。

なぜなら、コピー元に不良セクタがある場合、ddコマンドは、読み出しエラーが起きた時点で、コピーを終了してしまうから、パーティションの内容の途中までしかコピーしてくれません。

200709107


そういうときは、ddに、convオプションを指定します。

conv=noerrorと指定すると、読み出しエラーがあっても処理を継続するようになります。ただし、読み出しエラーがあった箇所をすっとばして書き込むので、コピー先で、だんだんと、セクタの位置がずれていってしまいます。こういうときは、conv=noerror,syncと指定します。

えーと、以前、こんなのを書いたことがあって、その中で、ddでパーティション丸ごとコピーする話も入れておいたのですが・・・

magicrescueで壊れたHDDからデータだけ救出【最終手段】


今回、これが、なぜか、うまくいきませんでした。どういうわけか、途中から、セクタがずれていってしまうのです。

ちなみに、セクタのずれがないかどうかは、ddに、iseekオプションを指定して、適当な位置を無作為に指定して(ずれていないことを確認するだけなら、パーティションのおしまいのほうを選んで、同じデータか確認すれば、基本的にはいいはず)、ちまちまと調べてみました。きっと、もっとうまく方法はあるんでしょうけど。

コピー元のデータを確認
   dd if=/dev/ad10s4 bs=1m iseek=90000 count=1 | hd | head

コピー先のデータを確認
  dd if=/dev/ad14s4 bs=1m iseek=90000 count=1 | hd | head

てゆうなことを繰り返しながら、試行錯誤しているうちに気がついたんですが、bs=1mではなくて、bs=16kとか、もっと小さい値を指定すれば、ずれなくなりました。え~?!って感じですが、なんか、そうなりました。

bs=512なら、たぶん一番正確にコピーされるとは思うのですが、データ転送速度が1MBytes/sec程度しかでなくて、あまりにも遅すぎて、お話にならないので、やめておきました。

bsを大きくしていけば、最大で、40MBytes/sec以上でてました。「iostat 1」コマンドで確認できます。

200709108

しかし、セクタのずれる現象が気になったし、bs=16kにしても30MBtes/sec程度だったので、よしとすることにしました。

なぜずれちゃうんでしょうか? bsで指定したサイズ内でだけ、ずれてたのでしょうかね? どうも、そうとは思えなかったんですが。まあいいや。


● ブートローダは、個人的に気に入ってるMBMを入れた

これはとくにトラブルもなく、うまくいきました。

なにはともあれ、これで、やっとWindowsのCドライブの内容を、そっくりそのままコピーできて、新しいHDDでブートすることに成功しました。