2007年9月11日火曜日

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

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



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でブートすることに成功しました。




0 件のコメント:

コメントを投稿